Skip to content

discussion: Circuit breaker, exhaustion registry, and CreditLedger state is in-memory — resets per Cloudflare Worker invocation #65

@stackbilt-admin

Description

@stackbilt-admin

Context

Three core reliability subsystems store their state exclusively in instance fields:

Subsystem State fields File
CircuitBreaker consecutiveFailures, lastFailureAt, lastSuccessAt, primaryTrafficPct src/utils/circuit-breaker.ts
ExhaustionRegistry per-provider exhaustion map src/utils/exhaustion.ts
CreditLedger per-provider spend accumulators src/utils/credit-ledger.ts

In Cloudflare Workers, each invocation runs in an isolated context. The global singleton instances (defaultCircuitBreakerManager, defaultExhaustionRegistry) are re-created on every request. This means:

  • A provider that was OPEN after 5 consecutive failures appears CLOSED on the next request
  • QuotaExceededError marks a provider exhausted for 5 minutes, but that mark is lost instantly
  • Monthly budget spend in CreditLedger resets to zero each invocation

The package is described as "Cloudflare Workers native" — this is a fundamental gap for that use case.

What's already there

CreditLedger has snapshot() and restore() methods (src/utils/credit-ledger.ts:523–580) for persistence — but no equivalent exists on CircuitBreaker or ExhaustionRegistry, and none of the three are wired up automatically.

Proposed direction

  1. Add serialize() / deserialize() to CircuitBreaker and ExhaustionRegistry — lightweight JSON snapshots that callers can persist to KV or cache
  2. Document the CF Workers limitation in the README under Circuit Breaker and Cost Tracking sections — currently the package presents as fully Workers-native without noting this constraint
  3. Optional: provide a Durable Objects integration as a separate export or companion package — a DO that owns the circuit breaker state and is shared across invocations

Acceptance criteria for a minimal fix

  • CircuitBreaker exposes serialize(): string and static deserialize(json: string): CircuitBreaker
  • ExhaustionRegistry exposes equivalent snapshot/restore API
  • README documents that state does not persist across Workers invocations and how to wire up persistence
  • Example snippet showing KV-backed persistence in a Workers handler

Found by

Codebase audit (automated) — independently flagged by circuit-breaker and cost-tracking audit slices

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions