mastak
mastak

Reputation: 353

Tornado: catching exceptions inside asynchronous open

I have problem with method open of WebSocketHandler. I wrapped it with gen.coroutine for using async call inside (get access to redis). But got another problem, any errors inside open does not catches.

Example:

@gen.coroutine
def open(self):
    t = 8/0
    self._connection_id = yield self._generate_connection_id()
    self.write_message('...')

Method open is call inside WebSocketProtocol._run_callback :

def _run_callback(self, callback, *args, **kwargs):
    try:
        callback(*args, **kwargs)
    except Exception:
        app_log.error("Uncaught exception in %s",
                      self.request.path, exc_info=True)
        self._abort()

This method hasn't any decorator, so method open return future and this exception doesn't handled.

So how can I use async method inside open, and handle exceptions?

Upvotes: 0

Views: 351

Answers (1)

Ben Darnell
Ben Darnell

Reputation: 22154

As a general rule, coroutines can only correctly be called by other coroutines, so when overriding a method of a base class like WebSocketHandler.open, unless that method is a coroutine or is documented as "may be a coroutine" or "may return a Future", it is not safe to make it a coroutine. WebSocketHandler.open may not be a coroutine (as of Tornado 4.1).

You may spawn a coroutine from open() with IOLoop.spawn_callback:

def open(self):
    IOLoop.current().spawn_callback(self.async_open)

@gen.coroutine
def async_open(self):
    #...

Within async_open, you can handle errors as usual with try/except (spawn_callback also logs exceptions for you as a last resort). It is also your responsibility to deal with any timing issues that may arise between async_open and on_message or on_close, since those methods may be called before async_open completes.

Upvotes: 2

Related Questions