2013-05-25 8 views
11

Napisałem program, który ma współprogram nazwie okresowo z głównego ioloop tak:W Tornado, jak mogę zobaczyć wyjątki rasied w coroutine wywoływane przez PeriodicCallback?

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

Wyjście mogę to po prostu:

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

The raise Exception() jest ignorowana! Jeśli zmienię wywołanie zwrotne na

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

Dostaję pełny ślad stosu, tak jak oczekuję (i potrzebuję). W jaki sposób mogę uzyskać ślad stosu podczas korzystania z coroutine?

Odpowiedz

4

Nie rozumiem dokładnie, dlaczego, ale zmiana @gen.coroutine na @gen.engine umożliwia wyjątek, aby prawidłowo się rozwinął. Nadal działa również asynchronicznie.

+0

Do obsługi wyjątków gen.coroutine przechwytuje błędy "wyjątku". gen.engine tego nie rób. Zobacz http://stackoverflow.com/a/23502625/1066801 – M07

7

@tornado.gen.coroutine sprawia powrotu funkcji tornado.concurrent.Future obiektu, dzięki czemu nie trzeba zawinąć go w tornado.gen.Task ale można nazwać użyciem yield kluczowe:

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

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

Wyjątek w funkcji urządzone w ten sposób jest owinięty w tym tornado.concurrent.Future obiektu i może zostać zwrócony później przy użyciu metody exception(). W twoim przypadku tornado.ioloop.PeriodicCallback wywołuje twoją metodę wywołania zwrotnego, a potem po prostu wyrzuca zwrócony obiekt tornado.concurrent.Future wraz z zawartym w nim wyjątkiem. Aby wykryć wyjątek można użyć łańcucha numerem:

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

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

Ale w twoim przypadku to rzeczywiście łatwiej jest go złapać tylko po wrzuceniu:

#!/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 nie robi funkcja zwróci tornado.concurrent.Future więc wyjątki aren” t opakowane.

Powiązane problemy