Skip to content

客户端主动断开连接(broken pipe)被计入渠道失败并触发 key 熔断,导致健康渠道被误拉黑 #292

Description

@inkOrCloud

问题描述

客户端(如 codex / agent 客户端)在流式响应过程中主动断开连接时,ccx 会把这个 broken pipe 写错误记录为渠道/API Key 失败,计入 key 级熔断统计,导致正常的 key 被反复拉黑(5m→10m 恢复),进而拖垮同渠道的其他会话。

复现场景

  1. 客户端发一个流式请求(/v1/responsesstream:true),经 ccx 路由到某渠道
  2. 上游正常出流,但客户端因为自己的超时/取消逻辑(如客户端侧 90s/300s 的 stale 超时,实际任务本身需 220-270s)先断开连接
  3. ccx 向客户端写数据时收到 write tcp ...: broken pipe
  4. ccx 把这个 broken pipe 记为「响应处理失败」,触发 标记API密钥失败: <key> (失败次数: N, 恢复时间: 5m0s/10m0s)
  5. 客户端断开后自动重试 → 循环触发 → key 被 5m/10m 黑名单

日志证据

[Responses-Key] [session=xxx round=1] 警告: 响应处理失败: write tcp 172.23.0.6:3000->172.23.0.5:36022: write: broken pipe
[Responses-Key] 标记API密钥失败: ark-*** (失败次数: 1, 恢复时间: 5m0s)

关键点:上游本身没有失败(实测该模型首 token 6-11s 正常返回),纯粹是客户端主动断开,但 ccx 把它当成了上游/渠道错误。

影响

  • 客户端超时→断开→重试的循环会让一个健康渠道的 key 反复熔断,5m/10m 不可用
  • 渠道 key 被熔断期间,其他走该渠道的正常会话也一起失败
  • 单渠道模型(无备用)直接表现为「所有渠道都失败了」503

期望行为

客户端主动断开(broken pipe / 客户端侧 connection reset)不应计入 key/渠道的失败熔断统计,或至少应可配置(如 countClientCancelAsFailure: false)。这是客户端取消,不是上游故障。

相关佐证

  • 请求 Accept: application/json(非流式解析)与 "stream":true body 并存时也容易触发
  • 客户端 X-Stainless-Read-Timeout: 1800 表明 SDK 层 read 超时很长,断开是客户端应用层主动取消

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions