龙卷风:在异步打开中捕获异常
Tornado: catching exceptions inside asynchronous open
我对 WebSocketHandler 的方法 open 有疑问。
我用 gen.coroutine 包装它以便在内部使用异步调用(访问 redis)。但是遇到了另一个问题,open里面的任何错误都没有捕获。
示例:
@gen.coroutine
def open(self):
t = 8/0
self._connection_id = yield self._generate_connection_id()
self.write_message('...')
方法open在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()
此方法没有任何装饰器,因此方法打开 return future 且此异常未处理。
那么如何在 open 中使用异步方法,并处理异常?
作为一般规则,协程只能被其他协程正确调用,所以当重写基础 class 的方法时,如 WebSocketHandler.open
,除非该方法是协程或被记录为"may be a coroutine"或者"may return a Future",做成协程是不安全的。 WebSocketHandler.open
可能不是协程(从 Tornado 4.1 开始)。
您可以使用 IOLoop.spawn_callback
:
从 open() 生成协程
def open(self):
IOLoop.current().spawn_callback(self.async_open)
@gen.coroutine
def async_open(self):
#...
在 async_open
中,您可以像往常一样使用 try/except 处理错误(spawn_callback
也会为您记录异常,作为最后的手段)。您也有责任处理 async_open
和 on_message
或 on_close
之间可能出现的任何时间问题,因为这些方法可能会在 async_open
完成之前被调用。
我对 WebSocketHandler 的方法 open 有疑问。 我用 gen.coroutine 包装它以便在内部使用异步调用(访问 redis)。但是遇到了另一个问题,open里面的任何错误都没有捕获。
示例:
@gen.coroutine
def open(self):
t = 8/0
self._connection_id = yield self._generate_connection_id()
self.write_message('...')
方法open在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()
此方法没有任何装饰器,因此方法打开 return future 且此异常未处理。
那么如何在 open 中使用异步方法,并处理异常?
作为一般规则,协程只能被其他协程正确调用,所以当重写基础 class 的方法时,如 WebSocketHandler.open
,除非该方法是协程或被记录为"may be a coroutine"或者"may return a Future",做成协程是不安全的。 WebSocketHandler.open
可能不是协程(从 Tornado 4.1 开始)。
您可以使用 IOLoop.spawn_callback
:
def open(self):
IOLoop.current().spawn_callback(self.async_open)
@gen.coroutine
def async_open(self):
#...
在 async_open
中,您可以像往常一样使用 try/except 处理错误(spawn_callback
也会为您记录异常,作为最后的手段)。您也有责任处理 async_open
和 on_message
或 on_close
之间可能出现的任何时间问题,因为这些方法可能会在 async_open
完成之前被调用。