Internal server: Shutdown server via socket
This commit is contained in:
parent
c8b31637ef
commit
0e8949ff71
@ -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)
|
for signal_number in exit_signal_numbers:
|
||||||
signal.signal(signal.SIGINT, signal_handler)
|
signal.signal(signal_number, exit_signal_handler)
|
||||||
if os.name == "posix":
|
|
||||||
signal.signal(signal.SIGHUP, 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)
|
||||||
|
@ -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
|
||||||
|
@ -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")
|
||||||
|
Loading…
Reference in New Issue
Block a user