mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-17 20:32:25 +03:00
* fix(resilience): allow maxWaitMs=0 as disable sentinel for execution expiration
maxWaitMs normalization clamped the value to min:1, silently rewriting
an operator's 0 ("disable the limiter-managed execution deadline") into
1 — a 1ms expiration that killed every long-running job instantly. This
broke long-running reasoning models (GLM-5.2 with reasoning.effort=max
spends minutes before the first token, exceeding any practical
maxWaitMs; the TTB safety net is FETCH_TIMEOUT_MS, default 600s).
Fix: lower the floor to min:0 so 0 is preserved as the disable sentinel.
Issue #4165 follow-up.
Tests: 7/7 (resilience-normalize-maxwaitms-disable 5 + rate-limit-
maxwaitms-disable-execution 2). typecheck:core clean.
* fix(resilience): relax requestQueueSettingsSchema.maxWaitMs to allow 0
normalizeRequestQueueSettings already treats maxWaitMs=0 as an explicit
disable sentinel (queue-wait budget off), but the settings API schema
still rejected 0 with min(1), so an operator could never actually reach
the fix through PATCH /api/resilience. executionMaxWaitMs is untouched
(stays min(1) — separate field, separate decision, see #12902 item 4).
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* test(resilience): prove maxWaitMs=0 vs #12715's queue-wait gate behavior
Answers the open technical question from #12902's review: does a
GLOBAL maxWaitMs=0 reintroduce the unbounded-queue regression #12715
fixed (a request hanging ~6min until the client aborts)?
Evidence, exercising the real gate chatCore.ts actually calls
(accountSemaphore.acquireMany({ timeoutMs: requestQueue.maxWaitMs }),
not the Bottleneck reservoir the PR's own tests cover) under real
contention (maxConcurrency=1, two concurrent acquires):
- No: it does not hang. setTimeout(reject, 0) fires on the next
tick, so a second contending request is rejected with
SEMAPHORE_TIMEOUT in low milliseconds, never minutes.
- But it is also not a genuine 'no cap' — an operator setting 0
expecting 'wait as long as it takes' instead gets near-zero
tolerance for even momentary contention on any configured
concurrency gate (global/provider/account). This is a real
asymmetry vs. the Bottleneck reservoir path (where 0 truly means
unbounded) left for the maintainer to decide how to resolve —
not something this pass can decide unilaterally.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
---------
Co-authored-by: Jihyun Son <jihyun.son@sk.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>