programming mac example async python asynchronous tornado

example - tornado python mac



En Tornado, ¿cómo puedo ver Exceptions rasied en una corrutina llamada por PeriodicCallback? (2)

No entiendo exactamente por qué, pero cambiar @gen.coroutine a @gen.engine permite que la excepción se @gen.engine correctamente. Todavía funciona de manera asíncrona también.

Escribí un programa que tiene una coroutine llamada periódicamente desde el ioloop principal de esta manera:

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

El resultado que obtengo es simplemente:

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

¡La raise Exception() se ignora silenciosamente! Si cambio la devolución de llamada para ser solo

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

Obtengo un seguimiento de pila completo como espero (y necesito). ¿Cómo puedo obtener ese rastro de pila mientras uso coroutine?


@tornado.gen.coroutine hace que la función devuelva el objeto tornado.concurrent.Future para que no tenga que envolverlo en tornado.gen.Task pero puede llamarlo usando la palabra clave yield :

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

Una excepción en la función decorada de esta manera se tornado.concurrent.Future este objeto tornado.concurrent.Future y se puede devolver más tarde utilizando su método exception() . En su caso, tornado.ioloop.PeriodicCallback llama a su método de devolución de llamada y, después de eso, está simplemente tornado.concurrent.Future objeto tornado.concurrent.Future devuelto junto con la excepción que contenía. Para detectar una excepción, puede usar la llamada en cadena:

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

Pero en su caso, en realidad es más fácil simplemente atraparlo justo después de tirar:

#!/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 no hace que la función devuelva un tornado.concurrent.Future por lo que las excepciones no se envuelven.