2013-05-25 5 views
11

Ho scritto un programma che ha un coroutine chiamato periodicamente dalla principale ioloop in questo modo:In Tornado, come posso vedere le eccezioni risuonate in una coroutine chiamata da 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() 

L'output che ottengo è semplicemente:

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

Il raise Exception() viene ignorata! Se cambio la callback per essere solo

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

Ricevo una traccia stack completa come mi aspetto (e ho bisogno). Come posso ottenere quella traccia di stack mentre utilizzo la coroutine?

risposta

4

Non capisco esattamente perché, ma cambiare @gen.coroutine a @gen.engine consente all'eccezione di schiumare correttamente. Funziona ancora in modo asincrono.

+0

Per gestire le eccezioni, gen.coroutine rileva errori "Eccezione". gen.engine non farlo. Vedere http://stackoverflow.com/a/23502625/1066801 – M07

7

@tornado.gen.coroutine rende funzione di ritorno tornado.concurrent.Future oggetto in modo non c'è bisogno di avvolgere in tornado.gen.Task ma si può chiamare usando yield parola chiave:

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

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

Un'eccezione in funzione decorato questo modo è avvolto in questo oggetto tornado.concurrent.Future e può essere restituito in seguito utilizzando il suo metodo exception(). Nel tuo caso, tornado.ioloop.PeriodicCallback chiama il tuo metodo di callback e dopo di ciò getta via solo l'oggetto tornado.concurrent.Future restituito insieme all'eccezione contenuta. Per rilevare un'eccezione si può usare catena chiamante:

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

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

Ma nel tuo caso in realtà è più facile solo per prenderlo solo dopo aver lanciato:

#!/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 non fa funzione di restituire un tornado.concurrent.Future così eccezioni aren' t avvolto.