RealtimeSession.close 抛异常后 async for 不退出,关闭流程该如何收尾
一个任务负责关闭 Realtime 会话,另一个任务还在 async for 中接收事件。关闭任务已经报错,消费任务却一直等,进程停不下来。这种现象要检查事件队列的结束通知,而不只是 WebSocket 有没有重连成功。
RealtimeSession.close 抛异常后 async for 不退出,关闭流程该如何收尾
一个任务负责关闭 Realtime 会话,另一个任务还在 async for 中接收事件。关闭任务已经报错,消费任务却一直等,进程停不下来。这种现象要检查事件队列的结束通知,而不只是 WebSocket 有没有重连成功。
一个已修复的关闭失败路径
Agents SDK #5070 给出了不联网复现:让测试模型的 close 抛出异常,观察事件消费者是否退出。报告涉及 v0.22.2 和 main 9f6f6b10。
旧实现已经停止接收新事件,但底层 close 失败后,等待队列的消费者没有得到结束信号,于是继续等待永远不会到来的事件。示例中的 close failed 是人为注入的测试错误文本,实际网络关闭失败可以有别的消息。
#5172 于 2026 年 9 月 25 日合并:关闭开始时唤醒读者,已缓存事件可以被消费完,之后迭代结束。底层清理失败仍会返回给关闭调用者,并保留重试机会。
应用需要区分两个结果
“事件消费者已经结束”和“模型连接已经成功关闭”要分别记录。修复后前者可以完成,而后者仍可能失败。不要在看到 async for 退出后,就把关闭异常当作无关日志丢掉。
升级到包含修复的版本是首选。无法马上升级时,可以由创建消费任务的上层代码负责有界等待;关闭失败后取消并等待消费任务退出,同时处理实际传输资源的清理。避免只调用 cancel 而不等待任务完成,也不要静默忽略所有 CancelledError 以外的清理异常。
建议保留的回归场景
用官方 ScriptedRealtimeModel 的关闭错误注入能力,可以离线验证:
- close 的调用者仍能收到清理错误
- 等待事件的消费者能在限定时间内退出
- 关闭前排队的事件按预期处理
- 两个消费者并存时,都不会留在等待状态
- 再次尝试 close 时,仍有机会清理底层模型
这组断言能覆盖“关闭报错但应用仍可有序停止”的需求。PR 合并时间不等于首次发布版本,选定 SDK 后还应核对变更记录并重跑自己的并发测试。


