You need to enable JavaScript to run this app. Python asyncio搭配websockets 8.1时Future异常未检索处理问题
优惠活动
大模型
产品
解决方案
定价
更多

Python asyncio搭配websockets 8.1时Future异常未检索处理问题

异步WebSocket开发异常捕获异常:Future exception was never retrieved 根因与解决方案

基础开发环境

  • Python 3.6.1 运行环境
  • 依赖版本:websockets==8.1
  • 现有实现逻辑:基于asyncio事件循环封装TestConnection类,完成WebSocket连接建立、异步消息接收全流程;在run协程中通过asyncio.gather(..., return_exceptions=True)配置任务异常收集,按照文档预期,该配置会自动消费协程抛出的所有异常,无需额外捕获。

问题现象与对照测试结果

核心异常表现

  • 触发场景:主动断开网络时,底层抛出websockets.exceptions.ConnectionClosedError(错误码1006,代表连接内部异常关闭、无明确关闭原因)
  • 矛盾表现:
    • 控制台可以正常打印gather收集到的上述ConnectionClosedError异常结果,说明gather本身对外部业务任务的异常捕获是正常的
    • 控制台仍持续弹出Future exception was never retrieved的未检索Future异常告警

反常对照测试

将原本负责接收处理消息的on_data方法修改为:异步休眠5秒后直接抛出RuntimeError("on_data error raised")。完成修改后重新测试,上述未检索Future异常的提示会完全消失。

问题根因拆解

这一现象和大多数开发者对asyncio.gather的功能误解直接相关,并非gather配置失效:

  1. gather的异常捕获边界有明确限制
    asyncio.gather(return_exceptions=True)仅会捕获、自动消费直接传入参数列表的最外层协程/任务抛出的异常;对于任务执行链路中,由第三方库内部自行创建、未被当前业务代码await、未绑定结果检索回调的游离后台Future,gather完全没有监控和消费权限。
  2. websockets 8.1版本的内部实现特性
    该版本的WebSocket连接对象在初始化时,会把「底层TCP连接的读写状态监控逻辑」拆分为独立的内部Task挂到事件循环上,这部分Task不属于业务代码传给gather的接收任务范畴:
    • 当触发1006类无原因连接关闭时,这个内部监控Task会先抛出ConnectionClosedError,且该版本的实现没有给这个Task绑定任何异常检索回调,直接触发了asyncio的默认未检索异常告警
    • 对照测试中告警消失的原因:手动在on_data里抛RuntimeError的场景下,异常是从业务代码主动抛出的,websockets内部的连接关闭流程会走正常的优雅关闭分支,那个独立的内部监控Task会顺利执行完成、抛出可被正常消费的正常关闭异常,不会触发无回调的未检索异常分支。
  3. 为什么控制台能看到gather收集的异常?
    业务侧传给gather的异步接收任务,同样会因为底层连接断开抛出ConnectionClosedError,这部分异常被gather正常捕获、打印,和websockets内部游离Task抛出的异常完全是两个独立的异常实例,所以才会出现“一边正常打印捕获到的异常,一边弹未检索告警”的矛盾现象。

可落地的解决建议

  • 根源修复方案:websockets 8.1版本的这个内部异常未回收问题,已经在8.1.2及后续9.x稳定版本中被修复,升级到兼容Python 3.6的最新稳定补丁版本即可从根源消除告警。
  • 无升级权限场景的临时规避:
  • 为当前asyncio事件循环注册全局异常处理器,对预期内的1006连接关闭类异常做过滤,避免无意义的控制台刷屏;处理器逻辑中可以主动检索游离Task的异常,将预期内的异常标记为已消费,消除告警。
  • 在连接关闭的收尾逻辑中,通过websockets连接对象暴露的内部接口,获取其关联的内部监控Task,为其添加异常检索回调,确保Task抛出的所有异常都能被正常消费。
  • 开发注意点:不要将return_exceptions=True作为全链路异常捕获的银弹,它的作用域仅覆盖gather直接管理的业务任务,第三方库内部生成的游离Task异常,必须依赖库自身的异常接口、或者全局事件循环异常回调做兜底处理。

内容的提问来源于stack exchange,提问作者David Co

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.22 07:15:03