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) #
{
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