Files
PolyGateway/research-wiki/designs/issue8-stall-budget.md
T
iomgaa f3e06eac89 chore: register the issue #8 design and plan in the research wiki
Registration pages carry the chosen approach, why the split is by "which
budget the time consumes", the five rejected alternatives with reasons,
and the 3.6 correction found during independent verification.
2026-08-06 11:09:37 -04:00

3.3 KiB
Raw Permalink Blame History

type, node_id, title, date
type node_id title date
design design:issue8-stall-budget stall 判定改为非生产性等待口径 2026-08-06

stall 判定改为非生产性等待口径

全文: designs/2026-08-06-issue8-stall-budget-design.md(已批准 2026-08-06)|来源: Gitea issue #8 |实施: plan:issue8-stall-budget-plan

问题

timeout_s ≥ stall_window_s 时,一次耗满超时的请求即判 scope 死,max_attempts 静默失效(无报错无 warning)。stall_window_s 默认 300 极易被 TIMEOUT_S 追平,"只配 timeout 不配 stall"这种最常见写法正好踩中。

根因

两个预算重叠计费:真实尝试的耗时同时向重试预算(max_attempts)与 stall 预算(stall_window_s)计费,而后者更小,必然先耗尽。

选定方案

StallClock 让 stall 只累计非生产性等待。划分依据是"谁消耗重试预算",不是"是否发出请求"——烧 max_attempts 的时间不烧 stall_window_s,不烧 max_attempts 的时间(含 429 尝试本身)归 stall 治理。

关键理由:

  • 消除耦合而非守护耦合stall_window_stimeout_s 自此无关系,配置方不必心算 stall > timeout × retries
  • inf 语义因此不必改。新口径下"非生产性排队耗满窗口且 scope 从未出餐"判死本就正当,inf 从"有害恒真"回归为"正确的保守默认"。一次改动解决问题,优于两次改动互相牵制。
  • 取补集实现(总时间减 _attempt 耗时)而非逐处标记 sleep:埋点 7 处降到 3 处,且将来新增等待路径自动计入 stall,默认安全。

被否决的备选

备选 否决理由
装配期校验 stall_window_s > max(timeout_s)(issue 建议方向 1) 治标:把缺陷固化成配置契约。且约束值须为 timeout × max_attempts(本机 900s),使 stall 兜底迟钝到近乎失效——修好一个洞挖开另一个。仍挡不住残余情形
inf 不参与判死(issue 建议方向 2) 新口径下 inf 已无害。单独改它会制造冷启动兜底真空(429 免预算无其他兜底),并反转 test_both_windows_exceeded_raises_stalled 钉住的行为、与 CHS 蓝本分叉
逐处标记 sleep 埋点 7 处且默认危险:新增等待路径忘记标记即成 stall 盲区
给 embedding/ocr 补主循环 stall 判定 前提不成立。429 免预算是 chat 独有,embedding/ocr 无条件 fails += 1,两条循环路径均已封闭,补齐等于凭空新增判死路径
删除既有 ttft 装配校验 其理由虽已消失(TTFT 属生产性时间),但校验无害且不误拒合理配置;删除需动 ARCHITECTURE §7.3 契约 G6,超出本 issue 范围(人类定夺:保留并改注释)

实施期订正(§3.6)

初稿按"是否发出请求"划分,使 429 尝试两个预算都不烧(429 免重试预算,其耗时又算生产性)。排队型网关持满 timeout 才回 429 时实测挂 25.2 小时(301 次尝试),而改前只有 301s——把一个 bug 换成了更严重的 bug。由独立验证发现。订正为按"谁消耗重试预算"划分,429 尝试耗时退还 stall 账,实测回到 301s。

不变量

双条件结构、progress_age_s()inf 语义、429 免预算、退避与 jitter 公式、fail_fast 分支、AllSourcesExhausted 字段与 reason 取值全部未动——错误面零变更