[英]Why does asyncio.CancelledError need to be re-raised?
I have the following aiohttp
WebSocket handler:我有以下aiohttp
WebSocket 处理程序:
async def websocket_handler(request):
ws = None
if 'my-websocket-clients' not in request.app:
request.app['my-websocket-clients'] = []
print('Websocket connection starting', request.path, request.query)
try:
ws = aiohttp.web.WebSocketResponse(autoping=True, heartbeat=10.0, compress=True)
await ws.prepare(request)
request.app['my-websocket-clients'].append(ws)
print('Websocket connection ready', len(request.app['my-websocket-clients']))
async for msg in ws:
await websocket_message(request, ws, msg)
except asyncio.exceptions.CancelledError as e:
print('Websocket connection was closed uncleanly ' + str(e))
# ~~~~~~ re-raise here? ~~~~~~
except:
traceback.print_exc()
finally:
try:
await ws.close()
except:
traceback.print_exc()
if ws in request.app['my-websocket-clients']:
request.app['my-websocket-clients'].remove(ws)
print('Websocket connection closed', len(request.app['my-websocket-clients']))
if ws is None:
ws = aiohttp.web.Response()
return ws
According to the documentation , " In almost all situations the exception [asyncio.exceptions.CancelledError] must be re-raised "根据文档,“在几乎所有情况下,必须重新引发异常 [asyncio.exceptions.CancelledError] ”
Do I need to re-raise the exception in the location marked in the code?我需要在代码中标记的位置重新引发异常吗? This would require me to rewrite the code which removes the client from the client list.这将需要我重写从客户端列表中删除客户端的代码。 Would I also need to re-raise the catch-all except
block which comes after the asyncio.exceptions.CancelledError
block?我是否还需要重新引发asyncio.exceptions.CancelledError
块之后的全部except
块?
Why do I need to re-raise asyncio.exceptions.CancelledError
in the first place, if I should need to do that in this case?如果在这种情况下我需要这样做,为什么我首先需要重新引发asyncio.exceptions.CancelledError
? In which situations wouldn't I need to re-raise that exception?在哪些情况下我不需要重新提出该异常?
In case of catching CancelledError
, you need to be very careful.在捕获CancelledError
情况下,您需要非常小心。
Prior to Python 3.8
, it was easy to unintentionally suppress this error with code like this:在Python 3.8
之前,很容易用这样的代码无意中抑制这个错误:
try:
await operation()
except Exception:
log.error('Operataion failed. Will retry later.')
Since Python 3.8 CancelledError
is subclass of BaseException
and it is necessary to always explicitly handle this error:由于 Python 3.8 CancelledError
是BaseException
子类,因此有必要始终显式处理此错误:
try:
await operation()
except CancelledError:
# cleanup
raise
except Exception:
log.error('Opertaion failed. will retry later.')
The main issue here is that you cannot cancel a task that suppress CancelledError
.这里的主要问题是您无法取消取消CancelledError
的任务。
But, in any case, the recommendation to re-raise is not absolute and is given for the general case.但是,无论如何,重新加注的建议不是绝对的,而是针对一般情况给出的。 If you know what you are doing, you can handle the CancelledError
and finish the coroutine without throwing it again.如果您知道自己在做什么,则可以处理CancelledError
并完成协程,而不会再次抛出它。 It should be minded that when a task is cancelled, its cancellation will generally look like a chain of CancelledError
s, which will be thrown from the innermost await
call and thrown up the chain of await
s, and in this case, we break this chain, and must correctly handle this situation.需要注意的是,当一个任务被取消时,它的取消通常看起来像一个CancelledError
链,它会从最里面的await
调用抛出并向上抛出await
链,在这种情况下,我们打破这个链,并且必须正确处理这种情况。
In the case of the aiohttp
websocket handler, I think it is acceptable not to re-raise the CancelledError
if you ensure that the resources are cleaned up correctly and the handler exits.在aiohttp
websocket 处理程序的情况下,如果您确保正确清理资源并且处理程序退出,我认为不重新引发CancelledError
是可以接受的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.