Repository navigation
Description
🤖 Powered by ework · qwen3.8-27b
来源: #5164「上游首字节前卡住时静默持有客户端最长 12 分钟并燃烧宿主重试」——本单是该工作单的决策载体(修复方向 A/B/C + 默认阈值),不是新问题报告。无决策依赖的诊断部分(选项 B 内容)已先行开止血 PR(链接见 #5164 线程);若最终选 C,请拒掉该 PR。
查重: 无。按「decision request / first byte / stall timeout / watchdog」检索 open+closed,无同主题条目;#5164 本身是工作单。
一句话背景
上游在返回第一个响应字节之前卡住时,bili 现在会静默持有客户端连接最长 12 分钟(唯一硬杀是 UPSTREAM_TIMEOUT_MS 的 idle abort),30s first-byte 看门狗只 warn 且每 origin 每进程终身一次、之后永久沉默;宿主(dsh 实测 ~300s)先超时重试,每次重付全额 input tokens。机制与证据已在 #5164 钉死(对 master 逐条核实过)。
选项
A fail-fast + 可配置阈值:first-byte 看门狗到阈值即 abort 本次 upstream 请求并向客户端回 502 retryable=true(带 stage 说明),让宿主有意地、更早地重试,而不是静默持有到自己超时。阈值走 knob 纪律新增 network.firstByteTimeoutMs / BILI_FIRST_BYTE_TIMEOUT_MS(env > file > default),CONFIGURATION.md en/zh 双镜像;0 = 禁用(保持现 warn-only 姿态)。
- 代价:行为变更——以前可等到 12min 的请求现在在阈值处快速失败(old→new:pre-first-byte 等待上界 12min → 阈值,默认值见子选项);长 prefill 本地模型误杀由阈值取值 + Test Blind Spot Retrospective: Reinforcing Negative Assertion Discipline, Tightening Fake Upstream Strictness, Thin Inst | 测试盲区复盘:补反向断言纪律、假上游严格化、薄安装冒烟、形态矩阵与生命周期覆盖 #3617 双向测试控制。
B 只补诊断不改语义:去掉 per-origin 终身去重,改为每 (origin, session) 冷却窗口 warn(每个受影响 turn 各有日志行、跨 turn 不互相抑制、防刷屏保留)。客户端行为不变(仍被持有至 12min/宿主超时),token 燃烧环不变。该内容已作为止血 PR 先行实现(零行为风险,且是 A 验收标准②④的严格子集),链接见 #5164 线程。
C 维持现状:接受静默持有 + 终身一条 warn。
结构化八问
- 是什么问题:上游首字节前卡住时,bili 静默持有客户端最长 12 分钟,宿主超时重试每次全额重付 input tokens,日志没有任何一行能解释这次挂起。
- 什么原因导致的:两个独立机制——① pre-first-byte stall 没有有界快速失败(唯一硬杀是 12min idle abort,而宿主 ~300s 总是先放弃);② per-origin 终身去重 + wedge 期间 timer 不触发导致解除后首次 fire 烧掉唯一配额,诊断面在第一次 warn 后归零。
- 影响范围与严重程度(按选项):
- 现状(A/B 要改掉的):任何撞上 pre-first-byte stall 的会话——turn ≥300s~12min 不可用,宿主每次重试全额重付(实测 ~193k tokens/turn × N),日志零解释行;p1 档(成本爆炸 + 核心承诺失灵)。触发条件:上游在头到达前 stall(ccproxy 聚合未 flush / wedge 后陈旧 socket / undici 池异常,hop 定位待 [Bug][Codex] Temporary separator selected as compression endpoint, causing acp_status to silently fail to report ~180K t | [Bug][Codex] 临时分隔符被选作压缩端点,导致 acp_status 静默漏报约 18 万 token 可压缩历史 #5139 侧访问日志——不影响本决策)。
- A:波及所有走主 forward 路径的车道(plugin/proxy 同一路径);stall>阈值的 turn 从静默持有变为 ≤阈值 的快速 502,宿主更早且有意地重试。残留风险=长 prefill 本地模型误杀(由默认值子选项控制)。
- B:仅日志面(warn 频率「每 origin 每进程一次」→「每 (origin,session) 每 60s 至多一次」);客户端可见行为零变化;燃烧环保留。
- C:无变化。
- 怎么修复的(推荐 A 的修法思路):把现有 30s one-shot 看门狗从「只 log」升级为「log + abort」:到期 abort 该 fetch 的 AbortController(复用既有 clientAbort 链路),错误路径回 502 retryable、stage=first-byte-timeout;abort kind 不进 transport-retry 的 fail-fast 集合(不放大重试),计入 circuit failure 信号。诊断去重改造(B)已由止血 PR 先行落地,A 在其之上叠加,合计 ≤2 个 PR。
- 回归风险(按选项):
- A:① 长 prefill 误杀(prefill>阈值)→ 默认值选择 + 显式 knob + 双向测试(stall<阈值不 abort / stall>阈值 abort+502+每 turn 有日志 / 健康流 idle re-arm 不受影响);② 个别宿主对 502-retryable 语义处理不当 → 502 是标准网关语义,已知宿主(dsh/opencode/pi/codex)对 5xx 均重试,PR 内逐车道确认;③ 与 PR [PR] fix: wedged proxy self-exits instead of holding its port forever (#4762) #4784 in-process 看门狗交互——正交(不同层),PR 内核对。
- B:日志量增加(受 60s 冷却约束,上界 1 行/min/(origin,session));无客户端可见行为变化。
- C:无(但燃烧环持续)。
- 是否破坏缓存:不涉及——三个选项都不触碰 prefix cache/增量游标/去重键;A 的 502 发生在首字节之前,尚无缓存写入。
- 是否改了设计方向:A 在主 forward 路径引入「proxy 主动回有界快速错误」——与既有 egress fuse(413)、Provider 429 (concurrency-style limit): turn re-driven every few seconds for minutes, keeps the account pinned at the limit #4204 429-hold local reject 同一族,非架构转向;B/C 不涉及。
- 是否引入新配置:A 新增
network.firstByteTimeoutMs(+ envBILI_FIRST_BYTE_TIMEOUT_MS),默认见子选项,0=禁用;新字段缺席=默认值,无需迁移。B/C 不涉及。
默认阈值子选项(仅 A 下)
| 子选项 | 默认 | 效果 | 风险 |
|---|---|---|---|
| A-1(推荐) | 120s | 云端用户开箱即快速失败 | 未显式调高的本地长 prefill 用户在 prefill>120s 时收到 502(发版披露) |
| A-2 | 600s | 更保守,覆盖多数本地 prefill | 云端 stall 仍被持有 ~10min,燃烧环只部分缓解 |
| A-3 | 12min(不变) | 默认行为零变化,纯 opt-in | 等价于 B 的效果面,失去默认修复意义 |
推荐:A + A-1(默认 120s)。理由:① A 的意义就是默认打破「静默持有→宿主自超时→全额重付」燃烧环,A-3 使其失效;② 120s 约为云端正常 TTFT(秒级)的 10–50×,误杀裕量充足;③ 长 prefill 本地模型用户的逃生门已经存在(BILI_UPSTREAM_TIMEOUT_MS 的存在证明该群体有调参习惯),新 knob 调高路径清晰;④ 502+retryable 让宿主更早、有意识地重试(dsh 每个失败 turn 省 ~180s 墙钟时间),且 bili 侧日志同时有 warn + 502 error 两条解释行。
对比表
| 维度 | A(A-1) | B | C |
|---|---|---|---|
| 打破 token 燃烧环 | ✅(默认生效) | ❌ | ❌ |
| 消除分钟级静默持有 | ✅(≤120s 快速错误) | ❌ | ❌ |
| 恢复日志可解释性 | ✅(基于止血 PR) | ✅(止血 PR 本身) | ❌ |
| 行为变更/回归风险 | 中(长 prefill 误杀,可控) | 无(仅日志量) | 无 |
| 人工门禁 | 需要(本单) | 不需要(已实现) | 不需要 |
| 配置面 | +1 字段(en/zh 双镜像) | 无 | 无 |
状态:止血 PR(B 内容)已提交待 CI;A 等你拍板方向 + 默认值后进入实现。
Mirrored from ework issue #5262
Activity
ranxianglei commentedon Oct 30, 2026
(ai: vllm-qwen/qwen3.8-27b)
止血 PR(B 内容)已提交:#5260 —— 定向测试 10/10 + typecheck 本地绿,全量回归看 CI。若拍 A,该 PR 是其诊断地基(验收②④),在其之上叠加 fail-fast;若拍 C,请拒掉它。方向与默认值等你拍板。