Circuit Breaker
- Defaults
- States
- When the circuit is open
- Inspect circuit state
- Share state across workers
- Pair with retries and bulkhead
The circuit breaker is enabled by default and scoped per target origin. When an upstream starts failing, the breaker trips and short-circuits further calls so you stop wasting time and connections on a service that’s already down.
Defaults
| Option | Type | Default | Meaning |
|---|---|---|---|
enableCircuitBreaker |
boolean |
true |
Master toggle |
failureThreshold |
number |
5 |
Consecutive failures before the circuit opens |
successThreshold |
number |
2 |
Successes in HALF_OPEN required to close |
circuitTimeout |
number (ms) |
60000 |
Time in OPEN before a probe (HALF_OPEN) |
circuitBreakerStorage |
CircuitBreakerStorageConfig |
— | Optional shared state store |
const api = neutrx.create({
resilience: {
failureThreshold: 5,
successThreshold: 2,
circuitTimeout: 30_000,
},
});
States
| State | Behavior |
|---|---|
CLOSED |
Normal — requests flow through. |
OPEN |
Requests fail fast with NeutrxCircuitBreakerError; no network I/O. |
HALF_OPEN |
After circuitTimeout, a limited number of probe requests test recovery. Successes (successThreshold) close the circuit; a failure re-opens it. |
When the circuit is open
import { NeutrxCircuitBreakerError } from 'neutrx';
try {
await api.get('/users');
} catch (error) {
if (error instanceof NeutrxCircuitBreakerError) {
console.warn(`circuit open, retry after ${error.retryAfter}ms`);
}
}
| Field | Value |
|---|---|
code |
'CIRCUIT_OPEN' |
category |
'resilience' |
retryable |
false |
retryAfter |
ms until the next probe is allowed |
Don’t retry through an open circuit from application code — let it recover via its own timeout. Stacking app-level retries on top of the breaker defeats the purpose.
Inspect circuit state
api.getCircuitStatus('https://api.example.com/users');
// { state: 'OPEN', failures: 5, openedAt: 1718000000000, lastFailure: ... }
api.getCircuitStatus();
// Record<origin, CircuitStatus> for every tracked origin
api.on('request:error', ({ url, error }) => console.error(url, error.code));
Share state across workers
By default each process has its own breaker. To trip the circuit cluster-wide, supply a store:
const api = neutrx.create({
resilience: {
circuitBreakerStorage: {
store: sharedCircuitStateStore, // sync or async CircuitStateStore
scope: 'origin', // 'origin' (default) | 'global'
namespace: 'billing-api',
},
},
});
The store interface is get(key) / set(key, value) / optional delete / keys. Keys follow neutrx:{namespace}:circuit:{scope}:{target}. Core ships no Redis client — see Config Reference → Distributed State and the Redis adapter.
Pair with retries and bulkhead
Use all three together for critical upstreams:
const api = neutrx.create({
resilience: {
maxRetries: 2, // recover from transient blips
failureThreshold: 5, // give up fast once it's clearly down
circuitTimeout: 30_000,
maxConcurrent: 10, // bound pressure while it's slow
},
});
- Retries smooth over transient errors.
- Circuit breaker stops the bleeding once failures are sustained.
- Bulkhead keeps a slow upstream from starving everything else.
See Bulkhead Isolation and Retry Strategies.
Frequently asked questions
How does the Neutrx circuit breaker work?
Each origin has a breaker with three states: closed (requests flow), open (requests fail fast after the failure threshold is crossed), and half-open (a few probe requests test recovery before closing again). This stops hammering a failing upstream.
When does the circuit breaker open?
It opens when failures cross the configured threshold within the rolling window. While open, requests fail fast with NeutrxCircuitBreakerError instead of waiting on a dead upstream.
What is a half-open probe?
After the open cooldown elapses, the breaker moves to half-open and allows a limited number of probe requests. If they succeed it closes; if they fail it reopens, avoiding a flood of requests at a still-broken service.
Is circuit breaker state shared across workers?
Breaker state is per origin and can be shared across workers with a shared state backend, so one worker observing failures can trip the breaker for the whole pool.