/** * Per-provider circuit breaker — three-state machine (CLOSED → OPEN → * HALF_OPEN → CLOSED). Sits in front of `AIRouter`'s provider calls so a * down provider stops eating wall-clock budget on every turn. * * State is in-isolate (per-Worker-instance `Map`). Workers recycle every * few minutes, so breakers self-heal without needing KV-shared state. * Trade-off: a provider that's actually down won't propagate OPEN across * isolates, so each cold isolate pays one failure to learn. Acceptable * for the typical Workers fleet size. * * Thresholds are per error kind: * - `'429'` (rate limit) trips fast, recovers fast * - `'5xx'` / `'network'` / `'parse'` trip slower, recover slower * (provider really down) * - `'timeout'` sits in between * * Exponential backoff: each consecutive trip after the first doubles the * OPEN window, capped at `backoffMaxMs` per error bucket. The counter * resets to 0 once the breaker closes successfully (HALF_OPEN passes * `halfOpenSuccessesToClose` probes). */ export type CircuitState = 'CLOSED' | 'OPEN' | 'HALF_OPEN'; export type CircuitErrorKind = '429' | '5xx' | 'network' | 'timeout' | 'parse'; export interface CircuitBucketConfig { /** Failures of this kind, in `windowMs`, that trip the breaker. */ threshold: number; /** Rolling window over which failures are counted. */ windowMs: number; /** Initial OPEN duration (doubles on consecutive trips). */ openMs: number; /** Hard cap on the exponentially-backed-off OPEN duration. */ backoffMaxMs: number; } export interface CircuitBreakerConfig { rateLimit: CircuitBucketConfig; serverError: CircuitBucketConfig; timeout: CircuitBucketConfig; /** Successful probes in HALF_OPEN needed to fully CLOSE the breaker. */ halfOpenSuccessesToClose: number; } export interface CircuitMetrics { status: CircuitState; openMsRemaining: number; openCount: number; recentFailures: number; } export declare class CircuitBreaker { readonly config: CircuitBreakerConfig; readonly now: () => number; private readonly entries; constructor(config?: Partial, now?: () => number); /** * @returns true if a call to `provider` is allowed (CLOSED or HALF_OPEN, * or an OPEN window that has expired and gets promoted to HALF_OPEN). * * Side-effectful: an expired OPEN entry is transitioned to HALF_OPEN * here so the next call can probe. */ canCall(provider: string): boolean; /** Current status (may transition OPEN → HALF_OPEN as a side effect). */ stateOf(provider: string): CircuitState; recordSuccess(provider: string): void; recordFailure(provider: string, errorKind: CircuitErrorKind | string): void; /** Snapshot of every provider's current circuit state — for dashboards. */ metrics(): Record; /** Force-reset one provider (admin / test only). */ reset(provider: string): void; /** Drop every cached entry (test helper). */ clear(): void; private entry; } //# sourceMappingURL=circuit_breaker.d.ts.map