diff --git a/tornado/concurrent.py b/tornado/concurrent.py index 702aa352b2..6bab5d2e0a 100644 --- a/tornado/concurrent.py +++ b/tornado/concurrent.py @@ -29,6 +29,7 @@ from tornado.stack_context import ExceptionStackContext, wrap from tornado.util import raise_exc_info, ArgReplacer +from tornado.log import app_log try: from concurrent import futures @@ -173,8 +174,11 @@ def _check_done(self): def _set_done(self): self._done = True for cb in self._callbacks: - # TODO: error handling - cb(self) + try: + cb(self) + except Exception: + app_log.exception('exception calling callback %r for %r', + cb, self) self._callbacks = None TracebackFuture = Future diff --git a/tornado/gen.py b/tornado/gen.py index 4bb82d422c..d0d0b5ef25 100644 --- a/tornado/gen.py +++ b/tornado/gen.py @@ -109,7 +109,10 @@ def final_callback(future): raise ReturnValueIgnoredError( "@gen.engine functions cannot return values: %r" % (future.result(),)) - future.add_done_callback(final_callback) + # The engine interface doesn't give us any way to return + # errors but to raise them into the stack context. + # Save the stack context here to use when the Future has resolved. + future.add_done_callback(stack_context.wrap(final_callback)) return wrapper