Search code examples
pythonsignalssocketserver

Python 2 does not handle signals if TCPServer is running in another thread


While playing with standard library i've found a strange difference between python2 and python3. If i try to catch a signal in python2 while TCPServer is running in a different thread the signal does not get handled, but in python3 it does.

Here is a script that reproduces the problem

import signal
import threading
import sys 
if sys.version_info > (3,0):
    from socketserver import TCPServer, BaseRequestHandler
else:
    from SocketServer import TCPServer, BaseRequestHandler

def shutdown(signum, frame):
    print("Shutting down server thread")
    server.shutdown()

server = TCPServer(
    ('127.0.0.1', 7654),
    BaseRequestHandler
)
signal.signal(signal.SIGTERM, shutdown)
signal.signal(signal.SIGINT, shutdown)
server_thread = threading.Thread(target=server.serve_forever)
print("Starting server thread")
server_thread.start()
print("Waiting for server thread to shut down")
server_thread.join()
print("Server thread terminated")

This is the output from python3:

Starting server thread
Waiting for server thread to shut down
^CShutting down server thread
Server thread terminated

And this is from python2:

Starting server thread
Waiting for server thread to shut down
^CKilled

"^C" is a keyboard interrupt and "Killed" is sigkill that i sent to a process.

Why shutdown was not called?


Solution

  • For me it seems thread.join() makes some lock and prevents from catching the signal.

    I've tested the following code in Python 2.7 and it seems to work:

    import time
    import signal
    import threading
    import sys 
    if sys.version_info > (3,0):
        from socketserver import TCPServer, BaseRequestHandler
    else:
        from SocketServer import TCPServer, BaseRequestHandler
    
    def shutdown(signum, frame):
        print("Shutting down server thread")
        server.running = False
        server.shutdown()
    
    server = TCPServer(
        ('127.0.0.1', 7654),
        BaseRequestHandler
    )
    signal.signal(signal.SIGTERM, shutdown)
    signal.signal(signal.SIGINT, shutdown)
    server_thread = threading.Thread(target=server.serve_forever)
    print("Starting server thread")
    server_thread.start()
    server.running = True
    print("Waiting for server thread to shut down")
    
    while server.running:
        time.sleep(1)
    
    server_thread.join()
    print("Server thread terminated")