Python script don't receive exit signal sent by supervisor
Question: I'm running a python script that creates a Tornado server, the server is run
by supervisor. I want to gracefully terminate all WebSocket client connections
when a **supervisorctl reload** is issued (normally after a deploy).

My problem is that I'm not able to get a function called when my server is
killed by supervisor, but it works when using kill with the signal or run on
console and killed with Control+C. I have tried other signals and
configurations without luck.

    
    
    import signal, sys
    
    def clean_resources(signum, frame):
        print "SIG: %d, clean me" % signum
        sys.exit(0)
    
    if __name__ == '__main__':
    
        # Nicely handle closing the server
        for sig in (signal.SIGINT, signal.SIGTERM):
            signal.signal(sig, clean_resources)
    

This is my tornado_supervisor.conf

    
    
    [program:tornado_server]
    command = python /opt/tornado/server.py -p 8890
    user = www-data
    stdout_logfile = /var/log/tornado/tornado_server_sup.log
    redirect_stderr = true
    autorestart=true
    environment=HOME='/var/www'
    environment=PYTHONPATH="$PYTHONPATH:/opt/tornado/"
    stopsignal = TERM
    stopwaitsecs = 10
    stopasgroup = true
    


Answer: I had similar/same problem. Only parent Tornado process got the signal, while
children processes where not killed.

I made arrangement that parent process kills children manually using
os.killpg(), also, children uses some delays to (possibly) finish current
requests:

    
    
    #will be initialized in main()
    server = None
    loop = None
    
    def stop_loop():
        global loop
        loop.stop()
    
    def signal_handler_child_callback():
        global loop
        global server
        server.stop()
        # allow to finish processing current requests
        loop.add_timeout(time.time() + LOOP_STOP_DELAY, stop_loop)
    
    def signal_handler(signum, frame):
        global loop
        global server
        if loop:
            #this is child process, will restrict incoming connections and stop ioloop after delay
            loop.add_callback(signal_handler_child_callback)
        else:
            #this is master process, should restrict new incomming connections
            #and send signal to child processes
            server.stop()
            signal.signal(signal.SIGTERM, signal.SIG_DFL)
            os.killpg(0, signal.SIGTERM)
    
    
    def main():
      parse_command_line()      
      signal.signal(signal.SIGTERM, signal_handler)
    
      # ...
    
      tornado_app = tornado.web.Application(
          [
              #...
          ])
    
      global server 
      server = tornado.httpserver.HTTPServer(tornado_app)
      server.bind(options.port)  
      server.start(0)
      global loop
      loop = tornado.ioloop.IOLoop.instance()
      loop.start()
    
    if __name__ == '__main__':
      main()
    

