Capacity-Protecting Circuit Breaker

A circuit breaker preserves caller capacity when a dependency is already known to be unhealthy. It is a load-control boundary, not a substitute for timeouts or recovery.

Reliability · TypeScript

Capacity-Protecting Circuit Breaker

A dependency failure should consume a bounded share of caller capacity, not every available request slot.

type State = { mode: 'closed' | 'open' | 'half-open'; failures: number; retryAt: number }

async function protectedCall<T>(key: string, operation: () => Promise<T>) {
  const state = await breaker.read(key)
  if (state.mode === 'open' && Date.now() < state.retryAt)
    throw new DependencyUnavailable(key)

  // compare-and-set admits one half-open probe across the fleet
  if (state.mode === 'open' && !await breaker.tryProbe(key, state))
    throw new DependencyUnavailable(key)

  try {
    const result = await operation()
    await breaker.recordSuccess(key)
    return result
  }
  catch (error) {
    await breaker.recordFailure(key, classify(error))
    throw error
  }
}

Invariant: When open, no ordinary request reaches the unhealthy dependency; probes remain bounded.

Use when: A failing dependency must not consume every caller slot and deadline.

Why this boundary matters

Waiting on a dependency already known to be unhealthy consumes threads, sockets, deadlines, and retry capacity needed for recovery.

Failure policy

BoundaryAction
Closed and below failure thresholdCall the dependency and record the outcome
Threshold exceededOpen for a bounded interval and fail fast
Open interval elapsedPermit one probe, not a traffic surge
Probe succeedsClose only after the recovery threshold
Probe failsReopen with a capped delay
Operation is an unsafe writeDo not hide ambiguity behind breaker fallback

Trade-offs

A breaker protects caller capacity and the dependency, but stale thresholds can reject healthy traffic or admit too much during a gray failure. Scope it by dependency and operation; combine it with deadlines, concurrency limits, and observability.

Decision rule: Use a circuit breaker when repeated calls to an unhealthy dependency would consume meaningful shared capacity and a fast failure has a defined product behavior.

Further reference

Browse all engineering snippets · Read about deadline budgets

>