• v1.2.4 f31f7caf99

    1.2.4 Stable

    iomgaa released this 2026-08-20 16:01:11 +08:00 | 91 commits to main since this release

    熔断开路时,调用方第一次可以选择而不是当场失败(issue #14)。此前准入侧有一格是空的:限流闸满时库允许排队({SCOPE}__QUOTA_FULL=wait|fail_fast,缺省 wait),熔断门拒绝时只有 fail-fast 一档且不可配——而两者在准入语义上是同构的,都没发出请求、都带着"稍后再来"的提示。新键 {SCOPE}__CIRCUIT_OPEN=fail_fast|wait 补上这一格,形状与 QUOTA_FULL 逐项对齐。

    缺省是 fail_fast,即今天的行为,存量部署无需改动任何配置。要改的是单源 scope:熔断的设计前提是"这个源坏了,把流量导到别的源",只配了一个源时这个前提不成立,同一段代码做的事就变成"这个源坏了,所以整个 scope 停止服务"。提交方实测:中转抖动 36 秒(22 次尝试 / 19 次 503)触发失败率通道开路,随后 30 次调用全部在 7-74 毫秒内失败,MAX_ATTEMPTS=8 一格没用上,一条跑了 3 小时 18 分钟的实验臂当场报废。配 wait 之后,熔断对配额和钱包的保护完整保留(等待期照样一个请求都不发),改变的只是调用方当场死还是排队等;代价是单次调用最坏墙钟被拉长——上限是 STALL_WINDOW_S(缺省 300 秒)。wait 并不豁免重试预算: 冷却结束后放行的探针是一次真实尝试,失败照样烧一格 MAX_ATTEMPTS,所以密钥失效(401/403)这类一击即熔的源通常更早以 reason=retry_exhausted 失败,而不是等满窗口后的 stalled;两者哪个先到取决于 MAX_ATTEMPTS 与冷却时长、STALL_WINDOW_S 的相对大小。库无法区分"密钥坏了"和"中转抖了",选 wait 就是声明"宁可等也不当场死"。

    请先读这一条: retry_after_s 在半开状态下的取值变了(缺省档同样生效)

    retry_after_s 从来没有写下来的定义,于是两个后端各自发挥、互相漂移。现在它只回答一个问题:距离确定可再试的时刻还有多久。健康与准入允许 → 0.0;开路 → 剩余冷却;半开(探针在途)→ 0.0,因为探针随时可能出结果,不存在确定的时刻——而 0 = 可立即重试 本就是这个字段的既有约定。

    变更点在半开:此前返回的是探针租约剩余。那是个死锁保护参数,派生自 max(2 × 最慢源 TIMEOUT_S, COOLDOWN_S, TIMEOUT_S + 5),与"这个源多久能恢复"没有任何因果关系。TIMEOUT_S=300 的部署里它是 600 秒,而冷却期只有 60 秒。照它延期重投的下游,等的是一个物理上无意义的数。

    更重的后果在库内,提交方也没发现:这个值被写进了源冷却备忘,而备忘的 set_until 取更晚者、不可回退。于是——源开路、冷却到期、调用①拿到探针、并发的调用②被拒并给该源记下 600 秒本地冷却、调用①的探针成功、门恢复 CLOSED——本进程此后仍然跳过这个健康的源将近 10 分钟。单源下每次调用照旧抛 CircuitOpenError;多源部署同样中招,只是别的源接住了流量,池子越大越隐蔽。修正后备忘写进的是一个已经过期的时刻,自动回到"只记开路的确定冷却期"。

    同批统一了两个后端在六个出口上的口径。其中四处是既有的分叉:Redis 在授予探针时返回探针 TTL、在写回被 fencing 拒时返回租约剩余,而内存后端一直返回 0。契约测试此前只钉了"第二个进入者会被拒绝",从没钉过它拿到的是什么数,这个盲区把分叉掩护到了今天。

    其他

    • _pick_runnable/_on_no_runnable 此前在 chat/embedding/OCR 三条治理循环里各存一份逐字复制,现收敛为 middleware/admission.py::SourceAdmission 一份。行为不变——差异用注入表达(调用内降权传空计数时恒等、AIMD pacer 为 None 时跳过),permit 结算的 warning 文案由三种归一为一种。
    • GatewayUnavailableError 的文档收回了重试职责:调用级的重试、退避、换源、等待冷却全部在库内,本异常表示那份预算已经用尽;下游据此再投属于任务级重试,语义不同。此前那句"业务侧 catch 本类做延期重投"读起来像在鼓励每个下游各写一份重试逻辑,而两边各写一份必然漂移。
    Downloads