fix: return 429 attempt time to the stall budget
Independent verification found the first cut had swapped one bug for a worse one. The budgets were split by "did we send a request", so a 429 attempt counted as productive — but 429 is exempt from the retry budget, so its time burned neither budget. Against a queueing gateway that holds the request for the full timeout before answering 429, a call could hang for 301 attempts / 25.2 hours, measured, versus 301 seconds before the change. The split is now by which budget the time consumes: time that burns max_attempts is excluded from stall, time that does not (429 attempts included) belongs to stall. Measured again: back to one attempt / 301s. Only the chat loop needs this — embedding and ocr count 429 against max_attempts unconditionally, so the gap never existed there. The stall verdict moved into _stalled(), which both call sites had duplicated, to keep __call__ under the complexity gate.
This commit is contained in:
@@ -328,6 +328,25 @@ class TestStallBudget:
|
||||
await mw(_REQ)
|
||||
assert ei.value.reason == "stalled" # 不是 retry_exhausted: 429 确实没烧重试预算
|
||||
|
||||
async def test_slow_429_does_not_escape_both_budgets(self):
|
||||
"""排队型网关: 持满 timeout 才回 429。该耗时必须落进 stall 账。
|
||||
|
||||
429 免重试预算, 所以它的耗时若又算生产性就**两个预算都不烧**——调用
|
||||
会挂满 stall_window/backoff_base 轮。修复前实测 301 次尝试、25.2 小时;
|
||||
此处钉住"一轮 429 就把 stall 账推满"这个上界。
|
||||
"""
|
||||
clock = FakeClock()
|
||||
src, limiter = self._free_limiter(clock)
|
||||
transport = ClockAdvancingTransport(
|
||||
[(_STALL + 1, TransientError("429", status_code=429))] * 20, clock
|
||||
)
|
||||
mw = _mw([src], limiter, [], clock=clock, sleep=BoundedSleep(), transport=transport)
|
||||
with pytest.raises(AllSourcesExhausted) as ei:
|
||||
await mw(_REQ)
|
||||
assert ei.value.reason == "stalled"
|
||||
# 一次持满超时的 429 即耗尽 stall 窗口, 不再无限排队
|
||||
assert len(transport.calls) <= 2
|
||||
|
||||
async def test_cancel_inside_attempt_pierces(self):
|
||||
"""取消发生在 `attempting()` 包裹内仍逐字穿透(库铁律)。"""
|
||||
clock = FakeClock()
|
||||
|
||||
Reference in New Issue
Block a user