Python脚本不接收主管发送的退出信号

时间:2014-08-12 13:23:30

标签: python signals tornado supervisord supervisor

我正在运行创建Tornado服务器的python脚本,服务器由主管运行。 我希望在发出 supervisorctl reload 时(通常在部署之后)优雅地终止所有WebSocket客户端连接。

我的问题是,当我的服务器被主管杀死时,我无法获得一个被调用的函数,但是当使用kill信号或在控制台上运行并使用Control + C终止时,它可以正常工作。 我没有运气就尝试过其他信号和配置。

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)

这是我的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

1 个答案:

答案 0 :(得分:0)

我有类似/同样的问题。只有父母Tornado进程才能获得信号,而子进程则处理未被杀死的信号。

我安排父进程使用os.killpg()手动杀死子进程,同时,子进程使用一些延迟来(可能)完成当前请求:

#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()