在Tornado中,我怎样才能看到在PeriodicCallback调用的协程中引发的异常?

时间:2013-05-25 00:03:51

标签: python asynchronous tornado

我写了一个程序,它有一个定期从主ioloop调用的协程,如下所示:

from tornado import ioloop, web, gen, log
tornado.log.enable_pretty_printing()
import logging; logging.basicConfig()

@gen.coroutine
def callback():
    print 'get ready for an error...'
    raise Exception()
    result = yield gen.Task(my_async_func)

l = ioloop.IOLoop.instance()
cb = ioloop.PeriodicCallback(callback, 1000, io_loop=l)
cb.start
l.start()

我得到的输出很简单:

$ python2 app.py
get ready for an error...
get ready for an error...
get ready for an error...
get ready for an error...

raise Exception()被默默忽略!如果我将回调更改为

def callback():
    print 'get ready for an error...'
    raise Exception()

我得到了一个完整的堆栈跟踪,就像我期望的那样(并且需要)。如何在使用协程时获得堆栈跟踪?

2 个答案:

答案 0 :(得分:7)

@tornado.gen.coroutine使函数返回tornado.concurrent.Future对象,因此您不必将其包装到tornado.gen.Task中,但可以使用yield关键字调用它:

@tornado.gen.coroutine
def inner():
    logging.info('inner')

@tornado.gen.coroutine
def outer():
    logging.info('outer')
    yield inner()

以这种方式修饰的函数中的异常被包装到此tornado.concurrent.Future对象中,稍后可以使用其exception()方法返回它。在你的情况下,tornado.ioloop.PeriodicCallback会调用你的回调方法,然后它就会丢弃返回的tornado.concurrent.Future对象及其包含的异常。要检测异常,您可以使用链调用:

@tornado.gen.coroutine
def inner():
    raise Exception()

@tornado.gen.coroutine
def outer():
    try:
        yield inner()   
    except Exception, e:
        logging.exception(e)

但是在你的情况下,只是在投掷之后抓住它就更容易了:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import tornado.gen
import tornado.ioloop
import tornado.options
import logging

tornado.options.parse_command_line()

@tornado.gen.coroutine
def callback():
    logging.info('get ready for an error...')
    try:
        raise Exception()   
    except Exception, e:
        logging.exception(e)

main_loop = tornado.ioloop.IOLoop.instance()
scheduler = tornado.ioloop.PeriodicCallback(callback, 1000, io_loop = main_loop)
scheduler.start()
main_loop.start()

@gen.engine不会使函数返回tornado.concurrent.Future,因此异常不会被包装。

答案 1 :(得分:4)

我不明白为什么,但将@gen.coroutine更改为@gen.engine可以让异常正确起泡。它仍然可以异步工作。