Circuit Breaker

  1. Defaults
  2. States
  3. When the circuit is open
  4. Inspect circuit state
  5. Share state across workers
  6. 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.


Back to top

Released under the MIT License. © Neutrx contributors.