You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在asyncio.wait中捕获WebSocket断开异常以实现优雅清理

解决WebSocket客户端断开时的优雅异常处理问题

首先,咱们直接说核心问题:你不需要用asyncio.wait()包裹websocket.send(),反而这个操作把异常藏在了Future对象里,导致你没法直接捕获。websocket.send()本身就是一个协程,当客户端断开连接时,它会直接抛出ConnectionClosedError,咱们直接await它并捕获异常就好。

正确的实现代码

from websockets.exceptions import ConnectionClosedError

async def status(websocket, message):
    try:
        print("\nDEBUG: "+message)
        await websocket.send(message)  # 直接await发送协程,无需asyncio.wait
    except ConnectionClosedError:
        # 在这里执行你的优雅清理逻辑:比如标记客户端离线、释放资源等
        print("客户端已异常断开,开始执行清理操作")
        raise Abort()  # 如果你需要用自定义异常终止上层流程

为什么你的原代码会出问题?

  1. 原代码的问题:
    你用await asyncio.wait([websocket.send(message)])时,asyncio.wait会将协程包装成Task,当发送操作抛出异常,这个异常会被存储在返回的Future中,而不是直接向上抛出,所以你的except块根本捕获不到它,最终导致Task exception was never retrieved的警告。

  2. 修改后代码的问题:
    你尝试通过Future获取异常,但判断条件写错了:future.exception() is websockets.ConnectionClosedError。这里future.exception()返回的是异常实例,而不是异常类,正确的判断应该是isinstance(future.exception(), websockets.ConnectionClosedError)。但其实完全没必要绕这个弯,直接await协程就能直接捕获异常。

额外说明

  • websocket.send()是协程函数,调用后返回协程对象,直接await它就能完成发送,同时连接断开时会直接抛出ConnectionClosedError,try-except块可以直接捕获。
  • asyncio.wait()适用于同时等待多个异步任务完成的场景,单个发送任务完全不需要用它,反而会增加异常处理的复杂度。

内容的提问来源于stack exchange,提问作者Vishal DS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:10:15