基于asyncio的库应该为关键错误处理提供什么API?

我正在使用 asyncio 编写一个库 . 在某些情况下,它会检测到电路错误并且无法继续 . 这不是一个错误,问题有外部原因 .

常规库代码会引发异常 . 程序将默认终止,但调用者也有机会捕获异常并执行清理或某种重置 . 这就是我想要的,但遗憾的是异常在asyncio中不起作用 . 更多关于:https://docs.python.org/3/library/asyncio-dev.html#detect-never-retrieved-exceptions

通知异步库用户有关问题的合理方法是什么?发生错误时可能会激活一些回调 . 用户可以进行必要的清理,然后在回调中退出 .

但是什么应该是默认动作?取消当前任务?停止整个事件循环?拨打 sys.exit

回答(1)

2 years ago

通常,不需要特定于错误的回调 . Asyncio完全支持在协同程序内的 await 边界之间传播异常,以及在同步和异步代码相遇的 run_until_complete 之类的调用中传播异常 . 当有人等待您的协程时,您可以通常的方式提出异常 .

一个陷阱是协同程序以"background tasks"运行 . 当这样的协程失败时,可能使库无法使用,没有人会自动得到通知 . 这是asyncio中的已知缺陷(详细讨论见here),目前为being addressed . 在此期间,您可以使用以下代码实现等效功能:

class Library:
    async def work_forever(self):
        loop = asyncio.get_event_loop()
        self._exit_future = loop.create_future()
        await self._exit_future

    async def stop_working(self):
        self._cleanup()
        self._exit_future.set_result(None)

    async def _failed(self):
        self._cleanup()
        self._exit_future.set_exception(YourExceptionType())

    def _cleanup(self):
        # cancel the worker tasks
        ...

work_forever 类似于serve_forever,一个可以被 main() 协程等待的调用,甚至直接传递给 asyncio.run() . 在这种设计中,库可以检测错误状态并传播异常,或者主程序(可能通过单独生成的协程)可以请求它干净地退出 .