0

So I am scheduling a callback using

ioloop.IOLoop.instance().add_timeout(time, callback_func)

But my callback_func may throw Exception which I want to catch.

Tried whats suggested in this answer but doesn't seem to work. Or maybe I am not doing it the right way. Any help on this would be great.

Code is somewhat like this:

start.py

class Start:
    # ... other methods ...
    @staticmethod
    def initialize():
        OtherClass.initialize()

def main():
    Start.initialize()

if __name__ == "__main__":
    main()

ioloop.IOLoop.instance().start()

other_class.py

class OtherClass:
    @staticmethod
    def initialize():
        ioloop.IOLoop.instance().add_timeout(time, callback_func)

    @staticmethod
    def callback_func():
        # Need to catch any exception which occurs here.
Community
  • 1
  • 1
pratpor
  • 1,954
  • 1
  • 27
  • 46

1 Answers1

1

If the callback_func is your own code, then by far the simplest way to catch all exceptions there is to simply wrap the whole function body in try / except:

@staticmethod
def callback_func():
    try:
        # ... your code ...
    except Exception as exc:
        # handle it

It's simple and everyone who reads your code will understand it, no surprises.

If you want to do something exotic and Tornado-specific, use an ExceptionStackContext:

from tornado import ioloop
from tornado.stack_context import ExceptionStackContext


class OtherClass:
    @staticmethod
    def initialize():
        ioloop.IOLoop.instance().add_timeout(1, OtherClass.callback_func)

    @staticmethod
    def callback_func():
        # Need to catch any exception which occurs here.
        1 / 0

class Start:
    # ... other methods ...
    @staticmethod
    def initialize():
        with ExceptionStackContext(Start.handler):
            OtherClass.initialize()

    @staticmethod
    def handler(exc_type, exc_value, exc_traceback):
        print("Caught %r in Handler" % exc_type)
        return True  # Tell Tornado that we handled it.

def main():
    Start.initialize()

if __name__ == "__main__":
    main()

ioloop.IOLoop.instance().start()

Best of all, use coroutines instead of callbacks. Coroutines are as efficient as callbacks, but give you regular Python exception handling semantics. See my article Refactoring Tornado Coroutines and the Tornado guide.

A. Jesse Jiryu Davis
  • 23,641
  • 4
  • 57
  • 70
  • Yes exception handling can be done in callback function itself, but thats not what I am looking for. Its done this way at so many other places, that I want to put a possible solution in common caller class `Start` so that I dont have to put `try except` for complete callback code or to put your other solution in other files being called from `Start` with similar callback. – pratpor Sep 19 '15 at 21:49
  • Your solution works well and as expected. Thanks. But could there be more generic solution which can be applied to base `Start` class. – pratpor Sep 19 '15 at 23:14
  • Edited my answer - I now show how you can move the handler into the Start class and use the ExceptionStackContext from Start.initialize instead of from OtherClass.initialize. – A. Jesse Jiryu Davis Sep 20 '15 at 13:34