Repository navigation
fix(providers): stop the loopback readiness gate from memorizing failure - #10903
Merged
diegosouzapw merged 2 commits intoAug 21, 2026
Merged
diegosouzapw merged 2 commits into
diegosouzapw merged 2 commits into
Conversation
maxmad64bis
force-pushed
the
fix/loopback-gate-memory-success
branch
from
August 20, 2026 22:20
756e299 to
8e596fa
Compare
added 2 commits
August 21, 2026 00:23
No-verify approved by the operator (2026-08-20): the check-docs-sync hook is broken on the base tip (8c4a219 desynchronized the i18n mirrors, 40+ locales, unrelated to this PR). The remaining hook gates were run manually: lint-staged PASS, any-budget PASS, tracked-artifacts PASS.
No-verify approved by the operator (2026-08-20): check-docs-sync is broken on the base tip (8c4a219), see previous commit.
maxmad64bis
force-pushed
the
fix/loopback-gate-memory-success
branch
from
August 20, 2026 22:23
8e596fa to
640b120
Compare
arminanton
added a commit
to arminanton/OmniRoute
that referenced
this pull request
Aug 21, 2026
Re-implements upstream diegosouzapw#10903 against the current release/v3.8.50 tip. ensureLoopbackServerReady cached __loopbackReadyPromise unconditionally, so a single failed readiness probe at boot cached a REJECTED promise forever. Every subsequent model-sync self-fetch then got that same rejection back (line 188 short-circuit), fell through to the in-process fallback permanently, and no probe ever ran again — the process never recovered even after the loopback listener came up moments later. Each waiting caller also logged the failure independently (~270 log lines in 26h, in bursts). Fix (src/app/api/providers/[id]/sync-models/route.ts): - Attach a .catch() to the readiness attempt that nulls __loopbackReadyPromise on rejection (only if it is still the current attempt), so the NEXT caller re-probes and the process self-heals. A resolved probe stays cached, so a healthy process still runs exactly one probe sequence (the boot-race dedup from P#2221 is preserved). - Throttle the readiness-failure warning to at most once per 60s across callers (warnReadinessFailureThrottled), so the now-possible re-probes don't amplify log volume. __resetLoopbackReadinessForTests resets the throttle too. Adds two regression tests to tests/unit/api/sync-models-readiness.test.ts: a failed probe is NOT memoized (a later call re-probes and resolves), and a successful probe IS memoized (one probe for a healthy process). Verified: sync-models-readiness 10/10 (8 existing + 2 new), model-sync-route 18/18, zai-web-model-sync-route 1/1; typecheck:core and lint clean. Fixes diegosouzapw#10903. Refs diegosouzapw#2221.
diegosouzapw
merged commit Aug 21, 2026
9b95282
into
diegosouzapw:release/v3.8.50
4 of 5 checks passed
arminanton
added a commit
to arminanton/OmniRoute
that referenced
this pull request
Aug 21, 2026
Re-implements upstream diegosouzapw#10903 against the current release/v3.8.50 tip. ensureLoopbackServerReady cached __loopbackReadyPromise unconditionally, so a single failed readiness probe at boot cached a REJECTED promise forever. Every subsequent model-sync self-fetch then got that same rejection back (line 188 short-circuit), fell through to the in-process fallback permanently, and no probe ever ran again — the process never recovered even after the loopback listener came up moments later. Each waiting caller also logged the failure independently (~270 log lines in 26h, in bursts). Fix (src/app/api/providers/[id]/sync-models/route.ts): - Attach a .catch() to the readiness attempt that nulls __loopbackReadyPromise on rejection (only if it is still the current attempt), so the NEXT caller re-probes and the process self-heals. A resolved probe stays cached, so a healthy process still runs exactly one probe sequence (the boot-race dedup from P#2221 is preserved). - Throttle the readiness-failure warning to at most once per 60s across callers (warnReadinessFailureThrottled), so the now-possible re-probes don't amplify log volume. __resetLoopbackReadinessForTests resets the throttle too. Adds two regression tests to tests/unit/api/sync-models-readiness.test.ts: a failed probe is NOT memoized (a later call re-probes and resolves), and a successful probe IS memoized (one probe for a healthy process). Verified: sync-models-readiness 10/10 (8 existing + 2 new), model-sync-route 18/18, zai-web-model-sync-route 1/1; typecheck:core and lint clean. Fixes diegosouzapw#10903. Refs diegosouzapw#2221.
diegosouzapw
pushed a commit
that referenced
this pull request
Aug 23, 2026
…nto v3.8.51) (#10952) Validated on the resolved merge against the current tip (527da65 + the post-#11281 rebaseline): the single conflict was a comment-only collision in providers/[id]/models/route.ts (kept the tip's #10828-ordering note). Focused suites 125/125 across all 13 touched test files (build-sqlite-stub, cc-compatible, copilot-claude-messages, copilot-gemini-route, executor-github, ghe-copilot, github-copilot-discovery-token, github-copilot-model-discovery, noauth-sibling-7620, provider-header-profiles, provider-models-config, request-log-payloads, upstream-error-passthrough), typecheck:core clean, file-size/changelog-integrity OK. Merged --admin over the inherited 2026-08-23 base-red cluster (#9985) — the reds are proven tip failures (CLI catalog cluster + @testing-library allowlist, being drained by #11280), not from this diff. Note: the rebase means several items the body listed (relay x-relay-path SSRF, /v1/search blocked-providers, #10736 rotation fence, #10903, #10865, #10899, #10916) already landed upstream and are NOT in this delta — the delta is: better-sqlite3 build guard + build heap/worker caps + telemetry-off (#10060 re-derived), credential-echo passthrough refusal + OCR/moderation redaction + call-log key redaction, Copilot CLI 1.0.81-6 wire identity + Claude→/v1/messages name-matched routing + discovery token fix, CC model_not_found 400, compat overrides for no-auth aliases (#7620-pinned). The Copilot wire-identity change is the one to watch in production. Thank you @arminanton — and the ported-author credits in the commit history (@rqzbeh, yidecode, the #10899/#10916 authors) are preserved. Your config-posture finding (REQUIRE_API_KEY default vs 0.0.0.0) is noted for a maintainer decision, as you scoped it.
muhamadgalihsaputra
pushed a commit
to niyatna/NiyatnaRoute
that referenced
this pull request
Sep 27, 2026
…ure (diegosouzapw#10903) Validado no worktree combinado: typecheck:core, changelog-integrity, complexity, cognitive-complexity, file-size, lint todos verdes. Fix real bem documentado (loopback readiness gate memorizava falha permanentemente + log-spam por caller). CI vermelho é o base-red já rastreado em diegosouzapw#9985. Obrigado!
muhamadgalihsaputra
pushed a commit
to niyatna/NiyatnaRoute
that referenced
this pull request
Sep 27, 2026
…nto v3.8.51) (diegosouzapw#10952) Validated on the resolved merge against the current tip (585c2b7 + the post-diegosouzapw#11281 rebaseline): the single conflict was a comment-only collision in providers/[id]/models/route.ts (kept the tip's diegosouzapw#10828-ordering note). Focused suites 125/125 across all 13 touched test files (build-sqlite-stub, cc-compatible, copilot-claude-messages, copilot-gemini-route, executor-github, ghe-copilot, github-copilot-discovery-token, github-copilot-model-discovery, noauth-sibling-7620, provider-header-profiles, provider-models-config, request-log-payloads, upstream-error-passthrough), typecheck:core clean, file-size/changelog-integrity OK. Merged --admin over the inherited 2026-08-23 base-red cluster (diegosouzapw#9985) — the reds are proven tip failures (CLI catalog cluster + @testing-library allowlist, being drained by diegosouzapw#11280), not from this diff. Note: the rebase means several items the body listed (relay x-relay-path SSRF, /v1/search blocked-providers, diegosouzapw#10736 rotation fence, diegosouzapw#10903, diegosouzapw#10865, diegosouzapw#10899, diegosouzapw#10916) already landed upstream and are NOT in this delta — the delta is: better-sqlite3 build guard + build heap/worker caps + telemetry-off (diegosouzapw#10060 re-derived), credential-echo passthrough refusal + OCR/moderation redaction + call-log key redaction, Copilot CLI 1.0.81-6 wire identity + Claude→/v1/messages name-matched routing + discovery token fix, CC model_not_found 400, compat overrides for no-auth aliases (diegosouzapw#7620-pinned). The Copilot wire-identity change is the one to watch in production. Thank you @arminanton — and the ported-author credits in the commit history (@rqzbeh, yidecode, the diegosouzapw#10899/diegosouzapw#10916 authors) are preserved. Your config-posture finding (REQUIRE_API_KEY default vs 0.0.0.0) is noted for a maintainer decision, as you scoped it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ensureLoopbackServerReadycaches__loopbackReadyPromiseand never forgets a rejection. The only reset path is a test helper. One failed probe at boot sends the whole process to the in-process fallback forever, and no probe ever runs again.Waiting callers also log the failure, each of them. That is 270 log lines in 26h for one probe, in five 54-line bursts.
This is the follow-up to P#2221. It removed the 17 concurrent probes; it left the single probe memorizing its failure and logging once per caller. This PR fixes both.
Related Issues
Validation
npm run lintTests Added Or Updated
tests/unit/api/sync-models-readiness.test.ts— three new cases: a failed probe is re-attempted after the retry window, 54 concurrent callers inside the window share one rejection, and a readiness failure is logged once per probe instead of once per caller.Run:
node --import tsx/esm --test tests/unit/api/sync-models-readiness.test.tsCoverage Notes
The three new tests cover the gate, the retry window and the transition log.
selfFetchWithRetrykeeps its existing coverage through the shared gate. The only mocks are an injectedfetchand aconsole.warnspy.Reviewer Notes