Exit immediately after cleanup when signal is received

Waiting for clients introduces the risk that we exceed some timeout (e.g. from systemd) and get killed instead.
This commit is contained in:
Unrud 2020-08-31 13:54:47 +02:00
parent 46c39b28d6
commit 30c9c55358
2 changed files with 16 additions and 17 deletions

View File

@ -27,7 +27,6 @@ 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
@ -36,10 +35,22 @@ from radicale.log import logger
def run(): def run():
"""Run Radicale as a standalone server.""" """Run Radicale as a standalone server."""
# Raise SystemExit when signal arrives to run cleanup code
# (like destructors, try-finish etc.), otherwise the process exits
# without running any of them
def signal_handler(signal_number, stack_frame):
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)
log.setup() log.setup()
# Get command-line arguments # Get command-line arguments
parser = argparse.ArgumentParser(usage="radicale [OPTIONS]") parser = argparse.ArgumentParser(
prog="radicale", usage="%(prog)s [OPTIONS]")
parser.add_argument("--version", action="version", version=VERSION) parser.add_argument("--version", action="version", version=VERSION)
parser.add_argument("--verify-storage", action="store_true", parser.add_argument("--verify-storage", action="store_true",
@ -137,17 +148,8 @@ 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()
# SIGTERM and SIGINT (aka KeyboardInterrupt) shutdown the server
def shutdown(signal_number, stack_frame):
shutdown_socket.close()
signal.signal(signal.SIGTERM, shutdown)
signal.signal(signal.SIGINT, shutdown)
try: try:
server.serve(configuration, shutdown_socket_out) server.serve(configuration)
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)

View File

@ -172,17 +172,14 @@ class TestBaseServerRequests(BaseTest):
config_args.append(long_name) config_args.append(long_name)
config_args.append( config_args.append(
self.configuration.get_raw(section, option)) self.configuration.get_raw(section, option))
env = os.environ.copy()
env["PYTHONPATH"] = os.pathsep.join(sys.path)
p = subprocess.Popen( p = subprocess.Popen(
[sys.executable, "-m", "radicale"] + config_args, env=env) [sys.executable, "-m", "radicale"] + config_args,
env={**os.environ, "PYTHONPATH": os.pathsep.join(sys.path)})
try: try:
self.get("/", is_alive_fn=lambda: p.poll() is None, check=302) self.get("/", is_alive_fn=lambda: p.poll() is None, check=302)
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")