Why does ctrl + c not stop tornado server?

2019-08-17 01:57发布

问题:

Why does ctrl + c not stop tornado server on windows ?

This code is not executed: print 'get sig:%d' % signum

import signal

import tornado
import tornado.web
import tornado.httpserver


class DefaultHandler(tornado.web.RequestHandler):

    def get(self):
        self.set_status(200, 'OK')
        self.write('hello guest')

    def post(self):
        self.get()


class Receiver(object):

    def __init__(self, address=None, port=8100, gzip=False):

        if not address:
            address = '0.0.0.0'
        self.address = address
        self.port = port
        self.gzip = gzip
        self.http_server = None

    def start(self):
        settings = dict(
        )
        application = tornado.web.Application([
            (r"/", DefaultHandler),],
            **settings)
        self.http_server = tornado.httpserver.HTTPServer(application, decompress_request=self.gzip)
        self.http_server.listen(self.port)
        tornado.ioloop.IOLoop.instance().start()

    def shutdown(self):

        if self.http_server is not None:
            self.http_server.stop()
        tornado.ioloop.IOLoop.instance().stop()


if __name__ == '__main__':
    receiver = Receiver(port=8901)

    def sig_handler(signum, frame):
        print 'get sig:%d' % signum
        receiver.shutdown()


    signal.signal(signal.SIGTERM, sig_handler)
    signal.signal(signal.SIGINT, sig_handler)
    receiver.start()

My solution:

only main thread can handle signal, so use thread to start receiver and let main thread do some fake work to keep alive

threading.Thread(target=receiver.start).start()
while 1:
    try:
        time.sleep(2)
    except:
        break

回答1:

Signal handlers are a special environment. You have to be careful what you do in one because you don't know the state of the functions that were interrupted by the signal. In tornado, only one function is guaranteed safe to call from inside a signal handler: IOLoop.add_callback_from_signal. Instead of calling shutdown() directly, use add_callback_from_signal to schedule it:

def sig_handler(signum, frame):
    IOLoop.current().add_callback_from_signal(receiver.shutdown)


回答2:

I wrote the more detailed answer here: https://stackoverflow.com/a/52941752/207661

In short, you need to install Ctrl+C handler for Windows manually.

Below are handy functions which will detect Windows and install custom handler for Ctrl+C in console:

#win_ctrl_c.py

import sys

def handler(a,b=None):
    sys.exit(1)
def install_handler():
    if sys.platform == "win32":
        import win32api
        win32api.SetConsoleCtrlHandler(handler, True)

You can use above like this:

import threading
import time
import win_ctrl_c

# do something that will block
def work():
    time.sleep(10000)        
t = threading.Thread(target=work)
t.daemon = True
t.start()

#install handler
install_handler()

# now block
t.join()

#Ctrl+C works now!


标签: tornado