[Bug] Codex API sidecar 首包超时后持续 504 / client_canceled,需重启 API 服务恢复
问题描述
Codex API 的 sidecar 在某次上游首包(stream_open)超时后,会间歇或连续返回 HTTP 504。Cockpit 将这类错误记录为 client_canceled / context canceled。出现后,需要重启 API 服务(即重启 cockpit-cliproxy sidecar)才能恢复;期间 FlClash 及代理本身仍可正常使用,也无需切换代理节点。
这看起来不是单次上游慢响应,而是超时后 sidecar 的连接池、请求上下文、账号调度或会话缓存没有被正确清理,导致进程进入异常状态。
可能与 #1791、#967 相关,但这里补充了固定超时节拍、重启恢复和配置未真正重载的证据。
环境
- Cockpit Tools:
1.3.16 - OS: Windows 11 专业版
10.0.26200x64 - Gateway mode:
sidecar - Model:
gpt-5.6-sol - Proxy:
http://127.0.0.1:7890(故障期间代理端口和其他网络请求正常) - OAuth 账号池: 3 个账号
- Routing:
round-robin - 当前相关配置:
stream-open-timeout-ms: 30000stream-open-max-attempts: 3stream-idle-timeout-ms: 300000keepalive-seconds: 15session-affinity: false(见下方“附加发现”)
实际表现
一次故障窗口内连续出现 4 次目标错误:
| 完成时间(UTC+8) | HTTP | 耗时 | 分类 | 错误 |
|---|---|---|---|---|
| 20:05:51 | 504 | 90.367s | client_canceled |
Post https://chatgpt.com/backend-api/codex/responses: context canceled |
| 20:07:22 | 504 | 90.384s | client_canceled |
同上 |
| 20:08:52 | 504 | 90.369s | client_canceled |
同上 |
| 20:10:23 | 504 | 90.368s | client_canceled |
同上 |
详细日志显示同一请求按约 30 秒的固定节拍重试三次,最终约 90.3 秒返回 504。这与 30 秒 × 3 次 的 sidecar 首包超时策略完全一致,因此 client_canceled 并不是客户端主动取消,而是 sidecar 的超时器取消请求上下文。
历史 debug 记录中,成功首包的 P99 约为 19.7 秒,最慢成功首包达到 34.291 秒,另一个为 29.740 秒。因此 30 秒阈值已经会取消至少一个原本能够成功的慢启动请求。
重启恢复证据
在不修改 FlClash、代理节点或系统网络的情况下,仅重启 Cockpit API 服务:
- 新 sidecar 进程于
20:12:59启动; - 随后的观察窗口中共 199 个请求:196 成功,3 个为 HTTP 200 下的正常客户端中途取消;
- 0 个 HTTP 502;
- 0 个 HTTP 504;
- 最长请求 56.358 秒。
这说明恢复动作主要清除了 sidecar 的进程内状态或旧连接,而不是修复了外部代理网络。
附加发现:配置保存后旧进程仍在服务
此前尝试关闭会话亲和时,sidecar 重启失败:
listen tcp 127.0.0.1:<port>: bind: Only one usage of each socket address ... is normally permitted.旧 sidecar 随后继续提供服务,导致界面/配置文件看似已经修改,但运行进程没有真正加载新配置。配置直到 20:12:58 再次写入并在 20:12:59 成功启动新进程后才生效。
期望行为
stream_open超时后应彻底释放/淘汰对应的请求上下文与 HTTP/TLS 连接,不应让后续请求持续复用异常状态。- 重试时应建立新连接,并排除刚刚发生首包超时的账号/凭据,避免重复命中同一异常路径。
- sidecar 自己触发的超时应分类为类似
upstream_stream_open_timeout,不应记录为client_canceled。 - 配置重启若因端口占用失败,界面应明确显示配置尚未生效,并确保旧、新进程切换是原子的。
- 建议默认首包阈值覆盖已观测到的 34.291 秒成功尾部,或将该阈值及重试策略明确暴露为可配置项。
复现说明
该问题为间歇性,通常发生在较长的 Codex 流式请求或上下文较大时:
- 使用 sidecar 网关发送
gpt-5.6-sol流式请求。 - 某次上游首包迟迟未返回。
- 观察到请求每 30 秒被取消并重试,三次后约 90 秒返回 504。
- 后续请求可能继续间歇或连续失败。
- 仅重启 API 服务后恢复,无需修改代理。
报告中的邮箱、API Key、完整账号 ID、请求正文和代理节点名称均已移除。
Source: jlcodes99/cockpit-tools