Skip to main content

Import

import { CircuitBreaker } from "bytekit/retry-policy";

What it does

CircuitBreaker implements the circuit breaker pattern to prevent cascading failures. When failures exceed a threshold, the breaker opens and immediately rejects calls for a cooldown period instead of overloading an already-failing service.
ApiClient creates an internal CircuitBreaker from the circuitBreaker config option. Use this class directly when you need circuit breaking outside of HTTP requests.

Constructor

const breaker = new CircuitBreaker(config?: CircuitBreakerConfig);

CircuitBreakerConfig

PropertyTypeDefaultDescription
failureThresholdnumber5Consecutive failures before the circuit opens.
successThresholdnumber2Consecutive successes in half-open state required to close the circuit.
timeoutMsnumber60000How long the circuit stays open before transitioning to half-open (ms).
errorMessageFormatter(retryAfterMs: number) => stringCustom formatter for the “circuit open” error message.

Methods

execute<T>(fn)

const result = await breaker.execute(() => callExternalService());
Runs fn if the circuit is closed or half-open. Throws immediately if the circuit is open and the timeout has not expired.
ParameterTypeDescription
fn() => Promise<T>The async function to protect.

getState()

const state = breaker.getState();
// "closed" | "open" | "half-open"
Returns the current state of the circuit.

reset()

breaker.reset();
Manually resets the circuit to the closed state, clearing all counters.

State machine

The circuit breaker cycles through three states:
┌────────┐  failures >= threshold   ┌────────┐
│ Closed │ ──────────────────────▶  │  Open  │
└────────┘                          └────────┘
    ▲                                   │
    │                                   │ timeout expires
    │                                   ▼
    │   successes >= threshold    ┌───────────┐
    └──────────────────────────── │ Half-Open │
                                  └───────────┘
StateBehavior
ClosedRequests pass through. Failures increment the counter.
OpenAll calls are rejected immediately with an error. The breaker waits for timeoutMs before moving to half-open.
Half-OpenA limited number of calls pass through. If successThreshold consecutive calls succeed, the circuit closes. Any failure re-opens it.

Examples

Basic usage

import { CircuitBreaker } from "bytekit/retry-policy";

const breaker = new CircuitBreaker({
  failureThreshold: 5,
  successThreshold: 2,
  timeoutMs: 30_000,
});

try {
  const data = await breaker.execute(() => fetchFromPaymentGateway());
} catch (err) {
  if (breaker.getState() === "open") {
    console.warn("Circuit is open — using fallback");
    return cachedData;
  }
  throw err;
}

Custom error message

const breaker = new CircuitBreaker({
  failureThreshold: 3,
  timeoutMs: 60_000,
  errorMessageFormatter: (retryAfterMs) =>
    `Service unavailable. Try again in ${Math.ceil(retryAfterMs / 1000)}s.`,
});

Combined with RetryPolicy

import { RetryPolicy, CircuitBreaker } from "bytekit/retry-policy";

const breaker = new CircuitBreaker({ failureThreshold: 5 });
const retryPolicy = new RetryPolicy({ maxAttempts: 3 });

const data = await breaker.execute(() =>
  retryPolicy.execute(() => fetchCriticalData()),
);
When using ApiClient, both retry and circuit breaker are configured together in the constructor — you don’t need to compose them manually.
The circuit breaker does not persist state across process restarts. In serverless or multi-instance environments, each instance maintains its own circuit state.