How OmniRoute's Cooldown and Backoff Mechanism Prevents Thundering Herd Problems
OmniRoute prevents thundering herd scenarios through a three-layer resilience system: exponential backoff per connection, provider-wide cooldown with circuit breaker protection, and intelligent failure deduplication.
The OmniRoute open-source router sits between applications and multiple LLM providers, orchestrating requests across connection pools. When failures occur—whether from rate limits, quota exhaustion, or transient errors—naive retry logic can trigger a thundering herd: thousands of requests hammering a struggling provider simultaneously. The project's cooldown and backoff architecture, implemented primarily in open-sse/services/accountFallback.ts, eliminates this risk through coordinated throttling at multiple scopes.
Exponential Backoff per Connection
Every connection in OmniRoute maintains an independent backoffLevel stored in the database. When a request fails, checkFallbackError in open-sse/services/accountFallback.ts triggers a backoff calculation via calculateBackoffCooldown:
// open-sse/config/errorConfig.ts
export function calculateBackoffCooldown(level = 0): number {
const safeLevel = Math.max(0, Math.floor(level));
const cooldown = BACKOFF_CONFIG.base * Math.pow(2, safeLevel);
return Math.min(cooldown, BACKOFF_CONFIG.max);
}
Base delay is 5 seconds, doubling with each retry: 5s → 10s → 20s → 40s. The maximum caps at 20 minutes (BACKOFF_CONFIG.max). The markAccountUnavailable() function persists both the incremented backoffLevel and a rateLimitedUntil timestamp. Subsequent request schedulers automatically exclude connections whose cooldown hasn't expired.
This per-connection spacing ensures no tight retry loops occur on individual keys or accounts.
Provider-Wide Cooldown and Circuit Breaker
When failures cluster across multiple connections for the same provider, OmniRoute escalates to provider-level protection. Each provider declares a resilience profile in open-sse/config/constants.ts:
| Profile Property | Purpose |
|---|---|
maxBackoffLevel |
Ceiling for connection-level exponential growth |
providerFailureThreshold |
Failure count triggering global cooldown |
providerCooldownMs |
Duration to block all provider traffic |
The recordProviderSuccess() and failure counterpart functions track provider-wide health. Once providerFailureThreshold is breached, setProviderCooldown() places the entire provider into cooldown. All connection selection logic skips that provider completely until providerCooldownMs elapses.
This provider-level cooldown acts as a circuit breaker, capping aggregate request volume even when dozens of accounts retry concurrently.
Failure Deduplication Against Spurious Spikes
Transient network events—a VPN blip, DNS hiccup, or regional connectivity issue—can cause many connections to fail simultaneously. Without deduplication, this would artificially inflate failure counters and trigger unnecessary provider cooldowns.
OmniRoute implements two deduplication windows in open-sse/services/accountFallback.ts:
CONNECTION_FAILURE_DEDUP_MS= 5 seconds — Ignores repeated identical failures from the same connectionNETWORK_ERROR_DEDUP_MS= 10 seconds — Filters duplicate network-level errors by provider
The shouldCountFailure() guard uses lastConnectionFailure and lastNetworkErrorByProvider Maps to remember recent timestamps:
// open-sse/services/accountFallback.ts
const CONNECTION_FAILURE_DEDUP_MS = 5_000;
const lastConnectionFailure = new Map<string, number>();
function shouldCountFailure(connKey: string): boolean {
const now = Date.now();
const last = lastConnectionFailure.get(connKey) ?? 0;
if (now - last < CONNECTION_FAILURE_DEDUP_MS) return false;
lastConnectionFailure.set(connKey, now);
return true;
}
This ensures single glitches don't cascade into system-wide backoff decisions.
Complete Failure Handling Flow
The thundering herd prevention mechanisms activate in sequence:
- Error classification —
findMatchingErrorRulecategorizes the failure (rate limit, server error, quota exhausted) - Backoff calculation —
calculateBackoffCooldowndetermines delay from current level - Connection marking —
setConnectionRateLimitUntilwrites cooldown to database - Provider health update — Increment counters; trigger cooldown if threshold exceeded
- Scheduler filtering — Connection picker respects both per-connection and provider-level blocks
Practical Configuration Examples
Applying per-connection backoff programmatically
import { calculateBackoffCooldown } from "@/open-sse/config/errorConfig";
import { setConnectionRateLimitUntil } from "@/lib/db/providers";
async function handleRateLimit(connId: string, currentLevel: number) {
const cooldownMs = calculateBackoffCooldown(currentLevel);
const nextLevel = currentLevel + 1;
await setConnectionRateLimitUntil(
connId,
Date.now() + cooldownMs,
nextLevel
);
}
Triggering provider-level protection
import { PROVIDER_PROFILES } from "@/open-sse/config/constants";
function evaluateProviderHealth(providerId: string, failureCount: number) {
const profile = PROVIDER_PROFILES[providerId];
if (failureCount >= profile.providerFailureThreshold) {
// 5-minute global cooldown for all provider connections
setProviderCooldown(providerId, profile.providerCooldownMs);
}
}
Key Source Files
| File | Responsibility |
|---|---|
open-sse/services/accountFallback.ts |
Core failure handling, deduplication, provider cooldown orchestration |
open-sse/config/constants.ts |
Provider resilience profiles and threshold definitions |
open-sse/config/errorConfig.ts |
calculateBackoffCooldown, error rule matching |
tests/unit/thundering-herd.test.ts |
Verification of backoff behavior under concurrent load |
src/lib/resilience/settings.ts |
Default resilience parameter defaults |
Summary
- Exponential backoff per connection spaces retries geometrically, preventing immediate reconnection storms
- Provider-wide cooldown caps aggregate load when multiple accounts fail together, functioning as a distributed circuit breaker
- Failure deduplication filters transient network glitches that would otherwise skew resilience decisions
- All mechanisms coordinate through
accountFallback.tswith state persisted inrateLimitedUntiltimestamps andbackoffLevelcounters
Frequently Asked Questions
What is a thundering herd in LLM routing?
A thundering herd occurs when many clients or retry loops simultaneously bombard a failing service with requests. In LLM routing, this happens when rate limits or server errors trigger immediate retries across hundreds of API keys, amplifying the original problem and potentially causing cascading failures downstream.
How does OmniRoute's backoff differ from standard retry libraries?
Standard libraries implement client-side backoff per request. OmniRoute adds stateful, cross-request coordination: backoff levels persist in the database, provider-wide cooldowns affect all connections simultaneously, and deduplication prevents correlated failures from triggering premature throttling. This makes it suitable for multi-tenant deployments with many concurrent users.
What triggers the provider-wide cooldown vs. individual connection backoff?
Individual connection backoff triggers on any classified failure (429, 5xx, quota exceeded). Provider-wide cooldown requires failures to accumulate across multiple distinct connections for that provider, exceeding providerFailureThreshold. The deduplication layer ensures a single network blip affecting many connections counts as one incident, not many.
Can the backoff parameters be customized per provider?
Yes. The PROVIDER_PROFILES configuration in open-sse/config/constants.ts allows per-provider customization of maxBackoffLevel, providerFailureThreshold, and providerCooldownMs. This lets you apply stricter limits to less reliable providers or relax them for premium tier services with higher capacity.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →