Circuit Breaker

Top-level circuit-breaker primitive. Re-exports the CircuitBreaker class otherwise reachable as b.retry.CircuitBreaker, plus a create(opts) factory matching every other framework primitive's create() shape. The implementation lives in lib/retry.js so the retry classifier and the breaker share the isRetryable / observability emit conventions; this module is the operator-facing surface so callers don't have to know retry is the breaker's home.

State machine: closed (normal flow; failures count up to failureThreshold), open (every call fast-fails for cooldownMs), half (one probe runs at a time and every other call fast-fails while it is in flight; each probe that succeeds counts toward successThreshold, which is 2 by default, and the breaker closes once that many have succeeded in a row, while one failure re-opens it immediately). Intended for per-target use, one instance per upstream service. Sharing a breaker across unrelated targets defeats the failure-threshold semantic.

b.circuitBreaker.create(opts) #

stable0.8.48
{
  name:             string,    // identifier used in audit + state-change events
  failureThreshold: number,    // failures in the closed state before opening
  cooldownMs:       number,    // milliseconds the breaker stays open before probing
  successThreshold: number,    // probe successes required to close from half-open
  onStateChange:    Function,  // ({ name, from, to, at }) → void; also emits the
                               //   `breaker.state.change` observability event
}

Build a circuit-breaker. Returns a CircuitBreaker instance with wrap(fn) (executes fn if the breaker is closed; throws a b.circuitBreaker.CircuitOpenError with code: "CIRCUIT_OPEN" + isCircuitOpenError: true + permanent: false when open, or when a half-open probe is already in flight), getState(), reset(), and onStateChange(handler) listener registration (the handler, and the onStateChange opt, receive { name, from, to, at } on every transition). Pass-through factory: identical instance shape to b.retry.CircuitBreaker, with the framework's create(opts) vocabulary.

The CIRCUIT_OPEN error code is not namespaced, unlike the rest of the framework. It is kept through the pre-1.0 line so operators who match err.code === "CIRCUIT_OPEN" keep working. It is renamed to a namespaced code at v1.0, with a deprecation warning shipping a minor ahead. isObjectStoreError is set on the error for the same reason, and isCircuitOpenError is the flag to match.

var cb = b.circuitBreaker.create({
  name:             "upstream-billing",
  failureThreshold: 5,
  cooldownMs:       30000,
  successThreshold: 2,
  onStateChange:    function (e) {
    // e = { name, from: "closed", to: "open", at:  }
  },
});

var result = await cb.wrap(async function () {
  return { ok: true, value: 42 };
});
result.value;     // → 42

Last updated 2026-10-12T14:21:56.879Z by seeder.