فهرست منبع

Internal server: Shutdown server via socket

Unrud 5 سال پیش
والد
کامیت
0e8949ff71
3فایلهای تغییر یافته به همراه23 افزوده شده و 6 حذف شده
  1. 20 6
      radicale/__main__.py
  2. 1 0
      radicale/server.py
  3. 2 0
      radicale/tests/test_server.py

+ 20 - 6
radicale/__main__.py

@@ -27,6 +27,7 @@ import argparse
 import contextlib
 import contextlib
 import os
 import os
 import signal
 import signal
+import socket
 import sys
 import sys
 
 
 from radicale import VERSION, config, log, server, storage
 from radicale import VERSION, config, log, server, storage
@@ -35,16 +36,20 @@ from radicale.log import logger
 
 
 def run():
 def run():
     """Run Radicale as a standalone server."""
     """Run Radicale as a standalone server."""
+    exit_signal_numbers = [signal.SIGTERM, signal.SIGINT]
+    if os.name == "posix":
+        exit_signal_numbers.append(signal.SIGHUP)
+        exit_signal_numbers.append(signal.SIGQUIT)
+    elif os.name == "nt":
+        exit_signal_numbers.append(signal.SIGBREAK)
 
 
     # Raise SystemExit when signal arrives to run cleanup code
     # Raise SystemExit when signal arrives to run cleanup code
     # (like destructors, try-finish etc.), otherwise the process exits
     # (like destructors, try-finish etc.), otherwise the process exits
     # without running any of them
     # without running any of them
-    def signal_handler(signal_number, stack_frame):
+    def exit_signal_handler(signal_number, stack_frame):
         sys.exit(1)
         sys.exit(1)
-    signal.signal(signal.SIGTERM, signal_handler)
-    signal.signal(signal.SIGINT, signal_handler)
-    if os.name == "posix":
-        signal.signal(signal.SIGHUP, signal_handler)
+    for signal_number in exit_signal_numbers:
+        signal.signal(signal_number, exit_signal_handler)
 
 
     log.setup()
     log.setup()
 
 
@@ -148,8 +153,17 @@ def run():
             sys.exit(1)
             sys.exit(1)
         return
         return
 
 
+    # Create a socket pair to notify the server of program shutdown
+    shutdown_socket, shutdown_socket_out = socket.socketpair()
+
+    # Shutdown server when signal arrives
+    def shutdown_signal_handler(signal_number, stack_frame):
+        shutdown_socket.close()
+    for signal_number in exit_signal_numbers:
+        signal.signal(signal_number, shutdown_signal_handler)
+
     try:
     try:
-        server.serve(configuration)
+        server.serve(configuration, shutdown_socket_out)
     except Exception as e:
     except Exception as e:
         logger.fatal("An exception occurred during server startup: %s", e,
         logger.fatal("An exception occurred during server startup: %s", e,
                      exc_info=True)
                      exc_info=True)

+ 1 - 0
radicale/server.py

@@ -61,6 +61,7 @@ class ParallelHTTPServer(socketserver.ThreadingMixIn,
 
 
     # We wait for child threads ourself
     # We wait for child threads ourself
     block_on_close = False
     block_on_close = False
+    daemon_threads = True
 
 
     def __init__(self, configuration, family, address, RequestHandlerClass):
     def __init__(self, configuration, family, address, RequestHandlerClass):
         self.configuration = configuration
         self.configuration = configuration

+ 2 - 0
radicale/tests/test_server.py

@@ -180,6 +180,8 @@ class TestBaseServerRequests(BaseTest):
         finally:
         finally:
             p.terminate()
             p.terminate()
             p.wait()
             p.wait()
+        if os.name == "posix":
+            assert p.returncode == 0
 
 
     def test_wsgi_server(self):
     def test_wsgi_server(self):
         config_path = os.path.join(self.colpath, "config")
         config_path = os.path.join(self.colpath, "config")