为什么 asyncio.CancelledError 需要重新加注?

Why does asyncio.CancelledError need to be re-raised?

我有以下 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

根据 the documentation,“在几乎所有情况下,必须重新引发异常 [asyncio.exceptions.CancelledError]

是否需要在代码中标记的位置重新抛出异常?这将需要我重写从客户端列表中删除客户端的代码。我是否还需要重新提出 asyncio.exceptions.CancelledError 块之后的包罗万象的 except 块?

为什么我首先需要重新加注 asyncio.exceptions.CancelledError,如果我在这种情况下需要这样做的话?在哪些情况下我不需要重新引发该异常?

万一被抓到CancelledError,要格外小心

Python 3.8 之前,使用如下代码很容易无意中抑制此错误:

try:
    await operation()
except Exception:
    log.error('Operataion failed. Will retry later.')

由于 Python 3.8 CancelledErrorBaseException 的子类,因此必须始终显式处理此错误:

try:
    await operation()
except CancelledError:
    # cleanup
    raise
except Exception:
    log.error('Opertaion failed. will retry later.')

这里的主要问题是您无法取消抑制的任务CancelledError

但是,无论如何,到re-raise的建议并不是绝对的,而是针对一般情况给出的。如果你知道自己在做什么,你可以处理 CancelledError 并完成协程而不会再次抛出它。应该注意的是,当一个任务被取消时,它的取消通常看起来像一串 CancelledErrors,将从 innermost await 调用中抛出并抛出了awaits的链条,在这种情况下,我们打破了这条链条,必须正确处理这种情况。

aiohttp websocket 处理程序的情况下,如果您确保正确清理资源并且处理程序退出,我认为不 re-raise CancelledError 是可以接受的.