Ratelock

Resilience Policies

withCircuitBreaker

Stop calling a failing backend to prevent cascading failures.

The withCircuitBreaker policy implements the circuit breaker pattern. When the backend fails too many times, it "opens" the circuit and immediately rejects requests without calling the backend, giving it time to recover.

Usage

import { fixedWindow, withCircuitBreaker } from '@ratelock/redis'

const limiter = await fixedWindow({ ... })
const circuitBreaker = withCircuitBreaker(limiter, {
    failureThreshold: 5,      // open after 5 consecutive failures
    recoveryTimeoutMs: 30_000, // wait 30s before trying again
})

Configuration Options

Prop

Type

States

StateBehavior
ClosedNormal operation. Requests go through to the backend.
OpenRequests are rejected immediately. No backend calls.
Half-OpenOne probe request is allowed. If it succeeds, the circuit closes. If it fails, the circuit reopens.

Error Context

When the circuit is open, the thrown error includes the last error as its cause:

try {
    await limiter.check('user:123')
} catch (err) {
    console.log(err.message) // "Circuit breaker is open"
    console.log(err.cause) // The original error that opened the circuit
}

Built-in Alternative

For most cases, use the built-in circuitBreaker option at creation time instead:

import { fixedWindow } from '@ratelock/redis'

const limiter = await fixedWindow({
    url: 'redis://localhost:6379',
    limit: 100,
    windowMs: 60_000,
    circuitBreaker: { failureThreshold: 5, recoveryTimeoutMs: 30_000 },
})

See Resilience Policies for when to use standalone vs built-in.

How is this guide?

Last updated on

On this page