Tornado异步回调异常

时间:2014-12-10 18:31:02

标签: python asynchronous tornado

我有一段同时执行的异步代码:

@tornado.web.asynchronous
def execute(self, func, *args):
    def callback(future):
        try:
            to_return = json.dumps(future.result())
            self.write(to_return)
            self.flush()
            self.finish()
        except:
            error = error = self.get_exception()
            self.set_status(500)
            self.finish(json.dumps({"error": error))

    EXECUTOR.submit(
        partial(func, *args)
    ).add_done_callback(
        lambda future: tornado.ioloop.IOLoop.instance().add_callback(
            partial(callback, future)))


def get_exception(self):
    exc_type, exc_obj, tb = sys.exc_info()
    f = tb.tb_frame
    lineno = tb.tb_lineno
    filename = f.f_code.co_filename
    linecache.checkcache(filename)
    line = linecache.getline(filename, lineno, f.f_globals)
    return {'error_msg': 'LINE {} "{}"): {}, {}'.format(filename, lineno, line.strip(), exc_obj, exc_obj)}

这很有效,除非在函数中某处抛出执行,堆栈跟踪只返回到它在回调中抛出的位置(即执行未来的位置),而不是它实际发生的位置代码。

是否有可能在最初抛出它的实际函数中捕获异常?

1 个答案:

答案 0 :(得分:1)

在python 3中,它应该正常工作;在python 2中你运气不好,虽然我认为你可以在ThreadPoolExecutor周围编写一个能够捕获更多细节的包装器。

Python的异常/回溯模型在Python 2和3之间发生了变化:在python 3中,Exception对象带有自己的回溯信息,而在python 2中,回溯是一个单独的对象(通常通过sys.exc_info三元组访问) )。由于concurrent.futures包是从Python 3反向移植的,它只捕获异常本身,而不是exc_info三元组,因此回溯丢失。

Tornado的未来类(tornado.concurrent.Future)有一些扩展来捕获python 2中的回溯(set_exc_info()方法)。我想你可以做这样的事情(未经测试)来替换executor.submit:

def submit_with_traceback(executor, func, *args):
    tornado_future = tornado.concurrent.Future()
    def wrapper():
        try:
            result = func(*args)
        except:
            tornado.future.set_exc_info(sys.exc_info())
        tornado_future.set_result(result)
    # executor.submit() returns a concurrent.futures.Future; ignore it
    executor.submit(wrapper)
    return tornado_future
相关问题