diff --git a/open-sse/services/accountFallback.ts b/open-sse/services/accountFallback.ts index 07c2f71506..a04f6a4b08 100644 --- a/open-sse/services/accountFallback.ts +++ b/open-sse/services/accountFallback.ts @@ -79,12 +79,12 @@ function toJsonRecord(value: unknown): JsonRecord { } // Provider-level failure tracking for circuit breaker behavior -// Error codes that count toward provider-level failure threshold -// 429 (rate limit) is intentionally excluded: rate limits are connection-scoped -// and handled via Connection Cooldown, not provider-wide circuit breaker. -// Counting 429 toward provider failure causes cascading provider trips at scale -// when many connections hit rate limits simultaneously (Issue #1846). -const PROVIDER_FAILURE_ERROR_CODES = new Set([408, 500, 502, 503, 504]); +// Error codes that count toward provider-level failure threshold. +// 429 is included: per-error-type cooldowns (rate_limit: 60s, quota_exhausted: 1h) +// prevent cascading provider trips at scale (Issue #1846 concern addressed), +// while still allowing the circuit breaker to open on sustained 429s and +// prevent infinite combo retries (Issue #3200). +const PROVIDER_FAILURE_ERROR_CODES = new Set([408, 429, 500, 502, 503, 504]); // Per-connection failure deduplication: prevents rapid-fire failures from the // same connection from counting multiple times toward the provider breaker. diff --git a/src/sse/handlers/chat.ts b/src/sse/handlers/chat.ts index 2e5efb681a..6e8f0415ae 100644 --- a/src/sse/handlers/chat.ts +++ b/src/sse/handlers/chat.ts @@ -173,7 +173,7 @@ function intersectAllowedConnectionIds(primary: unknown, secondary: unknown): st return first || second || null; } -const PROVIDER_BREAKER_FAILURE_STATUSES = new Set([408, 500, 502, 503, 504]); +const PROVIDER_BREAKER_FAILURE_STATUSES = new Set([408, 429, 500, 502, 503, 504]); /** * Handle chat completion request diff --git a/tests/unit/account-fallback-service.test.ts b/tests/unit/account-fallback-service.test.ts index 713a93440e..753e40e3ed 100644 --- a/tests/unit/account-fallback-service.test.ts +++ b/tests/unit/account-fallback-service.test.ts @@ -536,7 +536,7 @@ test("recordModelLockoutFailure uses provider profile cooldowns, backoff, and re // Provider-level failure circuit breaker tests test("isProviderFailureCode correctly identifies provider-wide transient error codes", () => { - assert.equal(isProviderFailureCode(429), false); + assert.equal(isProviderFailureCode(429), true); assert.equal(isProviderFailureCode(408), true); assert.equal(isProviderFailureCode(500), true); assert.equal(isProviderFailureCode(502), true);