【问题标题】:Stop Gracefully Tornado ioLoop优雅地停止 Tornado ioLoop
【发布时间】:2018-09-27 04:14:30
【问题描述】:

我使用 tornado 的 ioloop 拥有这个异步工作者功能。 我试图在 Ctrl+C 上优雅地关闭循环,但出现以下错误

tornado.ioloop.TimeoutError: 操作在无秒后超时

我知道我可以抓住它,但我确实想以一种优雅的方式完成这个过程,我该如何实现呢?

#!/usr/bin/env python
import time
import signal
import random

from tornado import gen, ioloop, queues

concurrency = 10

def sig_exit(signum, frame):
    ioloop.IOLoop.current().add_callback_from_signal(shutdown)

def shutdown():
    print('Will shutdown in few seconds ...')
    io_loop = ioloop.IOLoop.current()

    deadline = time.time() + 3

    def stop_loop():
        now = time.time()
        if now < deadline and (io_loop._callbacks or io_loop._timeouts):
            io_loop.add_timeout(now + 1, stop_loop)
        else:
            io_loop.stop()
            print('Shutdown')

    stop_loop()

@gen.coroutine
def main():
    q = queues.Queue()
    q.put(1)

    @gen.coroutine
    def do_stuff():
        print("doing stuff")
        yield gen.Task(ioloop.IOLoop.instance().add_timeout, time.time() + random.randint(1, 5))
        print("done doing stuff")

    @gen.coroutine
    def worker():
        while True:
            yield do_stuff()

    for _ in range(concurrency):
        worker()

    yield q.join()


if __name__ == '__main__':
    signal.signal(signal.SIGTERM, sig_exit)
    signal.signal(signal.SIGINT, sig_exit)

    io_loop = ioloop.IOLoop.instance()
    io_loop.run_sync(main)

【问题讨论】:

  • 您是否尝试在 Google 上搜索此主题?许多链接会弹出与此相关的讨论。但这里是来自 Ben Darnell 的 an answer,它发布在 Tornado 的邮件列表中。并且this question 这里的 SO 有一些与您的兴趣相关的代码和一个很好解释的答案。
  • @xyres 谢谢,我确实搜索过谷歌,大多数讨论嵌入在ioloop 中的http server 终止的主题没有找到像我的情况一样使用run_async 的人...

标签: python tornado sigterm ioloop


【解决方案1】:
async def main():
    tornado.options.parse_command_line()
    ...
    app = Application(db)
    app.listen(options.port)
        
    shutdown_event = tornado.locks.Event()
    def shutdown( signum, frame ):
        print("shutdown  database !!!!")
        db.close()
        shutdown_event.set()


    signal.signal(signal.SIGTERM, shutdown)
    signal.signal(signal.SIGINT, shutdown)

    await shutdown_event.wait()
    print("\n\nshutdown -h now")

if __name__ == "__main__":
    tornado.ioloop.IOLoop.current().run_sync(main)

【讨论】:

    【解决方案2】:

    如果您使用的是run_sync,则不能再致电IOLoop.stop - 现在由run_sync 负责。因此,如果你想让这个关闭“优雅”(而不是在你现在调用 stop() 的地方引发一个 KeyboardInterrupt 并退出堆栈跟踪),你需要更改传递给 run_sync 的协程以便它退出.

    一个可能的解决方案是tornado.locks.Event

    # Create a global Event
    shutdown_event = tornado.locks.Event()
    
    def shutdown():
        # Same as in the question, but instead of `io_loop.stop()`:
        shutdown_event.set()
    
    @gen.coroutine
    def main():
        # Use a WaitIterator to exit when either the queue 
        # is done or shutdown is triggered. 
        wait_iter = gen.WaitIterator(q.join(), shutdown_event.wait())
        # In this case we just want to wait for the first one; we don't
        # need to actually iterate over the WaitIterator. 
        yield wait_iter.next()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-05
      • 1970-01-01
      • 1970-01-01
      • 2019-11-10
      • 1970-01-01
      • 2010-12-15
      • 2018-09-08
      • 2021-06-04
      相关资源
      最近更新 更多