[projects/pld-builder.new] request_handler_server: graceful shutdown on SIGTERM/SIGHUP/SIGINT

arekm arekm at pld-linux.org
Sat Apr 25 16:39:11 CEST 2026


commit 346d1c6d771359bbbf28018b46a1d92a04805844
Author: Arkadiusz Miśkiewicz <arekm at maven.pl>
Date:   Sat Apr 25 16:11:17 2026 +0200

    request_handler_server: graceful shutdown on SIGTERM/SIGHUP/SIGINT

 PLD_Builder/request_handler_server.py | 71 +++++++++++++++++++++++------------
 1 file changed, 47 insertions(+), 24 deletions(-)
---
diff --git a/PLD_Builder/request_handler_server.py b/PLD_Builder/request_handler_server.py
index 74b90e1..5bcdaac 100644
--- a/PLD_Builder/request_handler_server.py
+++ b/PLD_Builder/request_handler_server.py
@@ -4,6 +4,7 @@ import socket
 import string
 import time
 import log
+import signal
 import ssl
 import sys
 import traceback
@@ -16,12 +17,27 @@ from socketserver import ForkingMixIn
 import request_handler
 import path
 
+_shutdown_signum = None
+
+def _on_shutdown_signal(signum, frame):
+    global _shutdown_signum
+    _shutdown_signum = signum
+
 class ForkingHTTPServer(ForkingMixIn, HTTPServer):
     # Each request runs in a forked child so a slow handler (GPG verify,
     # queue locking, SRPM processing) cannot block accept() of new clients,
     # which surfaced on TLS as _ssl.c:1015 handshake timeouts. Forking also
     # isolates module-level mutable state (acl.current_user, etc.).
-    pass
+
+    def finish_request(self, request, client_address):
+        # _on_shutdown_signal is inherited by the child, but it just sets a
+        # module-level flag the child never checks - so SIGTERM to a child
+        # would silently do nothing. Restore the default action so a stuck
+        # child can be terminated with kill -TERM rather than only SIGKILL.
+        signal.signal(signal.SIGTERM, signal.SIG_DFL)
+        signal.signal(signal.SIGHUP, signal.SIG_DFL)
+        signal.signal(signal.SIGINT, signal.SIG_DFL)
+        super().finish_request(request, client_address)
 
 class MyHandler(BaseHTTPRequestHandler):
 
@@ -93,31 +109,38 @@ def main(srv_ssl=False):
     write_css();
     write_js();
     socket.setdefaulttimeout(30)
+    # Default action for SIGTERM/SIGHUP is silent termination; for SIGINT
+    # it's KeyboardInterrupt. Capture all three through the same handler
+    # so the accept loop notices and runs server_close(), which reaps
+    # in-flight forked children.
+    signal.signal(signal.SIGTERM, _on_shutdown_signal)
+    signal.signal(signal.SIGHUP, _on_shutdown_signal)
+    signal.signal(signal.SIGINT, _on_shutdown_signal)
+    init_conf()
+    host = ""
+    port = config.request_handler_server_port
+    if srv_ssl:
+        port = config.request_handler_server_ssl_port
+
     try:
-        init_conf()
-        host = ""
-        port = config.request_handler_server_port
+        server = ForkingHTTPServer((host, port), MyHandler)
         if srv_ssl:
-            port = config.request_handler_server_ssl_port
-
-        try:
-            server = ForkingHTTPServer((host, port), MyHandler)
-            if srv_ssl:
-                context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
-                context.load_cert_chain(certfile=config.request_handler_server_ssl_cert,
-                                        keyfile=config.request_handler_server_ssl_key)
-                context.load_verify_locations(cafile="/etc/certs/ca-certificates.crt")
-                server.socket = context.wrap_socket(server.socket, server_side=True)
-        except Exception as e:
-            log.notice("request_handler_server: can't start server on [%s:%d], ssl=%s: %s" % (host, port, str(srv_ssl), e))
-            print >> sys.stderr, "ERROR: Can't start server on [%s:%d], ssl=%s: %s" % (host, port, str(srv_ssl), e)
-            sys.exit(1)
-
-        log.notice('request_handler_server: started on [%s:%d], ssl=%s...' % (host, port, str(srv_ssl)))
-        server.serve_forever()
-    except KeyboardInterrupt:
-        log.notice('request_handler_server: ^C received, shutting down server')
-        server.socket.close()
+            context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
+            context.load_cert_chain(certfile=config.request_handler_server_ssl_cert,
+                                    keyfile=config.request_handler_server_ssl_key)
+            context.load_verify_locations(cafile="/etc/certs/ca-certificates.crt")
+            server.socket = context.wrap_socket(server.socket, server_side=True)
+    except Exception as e:
+        log.notice("request_handler_server: can't start server on [%s:%d], ssl=%s: %s" % (host, port, str(srv_ssl), e))
+        print >> sys.stderr, "ERROR: Can't start server on [%s:%d], ssl=%s: %s" % (host, port, str(srv_ssl), e)
+        sys.exit(1)
+
+    log.notice('request_handler_server: started on [%s:%d], ssl=%s...' % (host, port, str(srv_ssl)))
+    server.timeout = 1.0
+    while _shutdown_signum is None:
+        server.handle_request()
+    log.notice('request_handler_server: %s received, shutting down server' % signal.Signals(_shutdown_signum).name)
+    server.server_close()
 
 if __name__ == '__main__':
     srv_ssl = False
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/projects/pld-builder.new.git/commitdiff/33d0188f0225eeed4f279d76812f280f6c83a2e8



More information about the pld-cvs-commit mailing list