A circuit breaker watches the failures of one dependency. When they cross a threshold it opens: calls fail at once with BrokenCircuitError instead of piling up on a service that can’t answer. After a break it lets a probe through, and closes again if the probe succeeds.
Use one breaker per downstream dependency, shared by every call to it (build the pipeline once, or use the registry). A breaker created per request never sees enough failures to open. Don’t use it for errors that say nothing about the dependency’s health, such as validation errors; the default predicate already ignores 4xx.
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
ResiliencePipelineBuilder adds Polly-style addRetry() / addTimeout() / … shortcuts on top, at the cost of
bundling every strategy. Strategies run in the order they are added: the first one added is the outermost.
Options are validated and strategy state (e.g. circuit breaker) is created on build().
ResiliencePipelineBuilder adds Polly-style addRetry() / addTimeout() / … shortcuts on top, at the cost of
bundling every strategy. Strategies run in the order they are added: the first one added is the outermost.
Options are validated and strategy state (e.g. circuit breaker) is created on build().
Opens when at least 50% of the last 10 calls failed (and at least 4 calls were recorded). While open, calls fail fast with BrokenCircuitError; after 3 s the next call is let through as a probe.
State
Calls
Leaves when
closed
Pass through. Each outcome is recorded as a success, a failure or ignored.
The opening rule fires after a failure → open.
open
Rejected with BrokenCircuitError (retryAfter = ms left).
The break is over and a call arrives → half-open. There is no timer: the next call triggers it.
half-open
Up to halfOpenMaxCalls probes pass; others are rejected (retryAfter: 0).
All probes finished → closed if they were healthy enough, else open again. A probe slower than halfOpenMaxWait counts as failed → open.
isolated
Rejected with IsolatedCircuitError.
Manual close only.
What counts. An outcome is a failure when shouldHandle matches it. The default matches errors except 4xx (408 and 429 do count), aborts and rejections. Successes count as successes. Everything else, such as a 404, is ignored: neither a failure nor a success. Rejections from other strategies (a full limiter, another open circuit) are never counted, whatever shouldHandle says.
Stale calls. A call that started before the circuit changed state can’t affect the new state when it finishes. A slow failure from before a reset won’t reopen the circuit.
Probes. With the default halfOpenMaxCalls: 1, one probe decides. With more, the circuit closes when the probes’ failure ratio stays below failureRatio, or, with halfOpenSuccessThreshold, when at least that fraction succeeded. An ignored probe outcome frees its slot for another probe.
total ≥ minimumThroughput and failures / total ≥ failureRatio over the last samplingDuration
Steady, high traffic.
Ratio, count window
failureRatio, minimumThroughput, samplingCount
Same, over the last samplingCount calls
Low or bursty traffic.
Consecutive
consecutiveFailures
That many failures in a row (a success resets the count)
Low traffic, simple setups.
Custom
breaker: CircuitBreakerPolicy
Your shouldOpen(now) returns true
Anything else.
Setting consecutiveFailureswithoutfailureRatio turns the ratio rule off. Set both and either one opens the circuit.
The time window is kept in 10 buckets, so old calls drop out in steps of samplingDuration / 10.
minimumRps (time window only) also requires that many calls per second on average over the window, so a quiet period’s few failures can’t open the circuit.
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
A CircuitBreakerPolicy replaces failureRatio, minimumThroughput and the window (consecutiveFailures still applies). Only calls made while closed are recorded. Use one instance per breaker; it holds that breaker’s history.
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
ResiliencePipelineBuilder, type
(alias) interfaceCircuitBreakerPolicy
importCircuitBreakerPolicy
Decides when a closed circuit opens (cockatiel's IBreaker). Only calls made while closed are recorded; now is the
pipeline's time provider. One instance per breaker: it holds that breaker's history.
CircuitBreakerPolicy } from'resilience-pipeline';
/** Open after 5 failures within one minute, whatever the success count. */
class
classFailuresPerMinute
Open after 5 failures within one minute, whatever the success count.
FailuresPerMinuteimplements
(alias) interfaceCircuitBreakerPolicy
importCircuitBreakerPolicy
Decides when a closed circuit opens (cockatiel's IBreaker). Only calls made while closed are recorded; now is the
pipeline's time provider. One instance per breaker: it holds that breaker's history.
Returns the elements of an array that meet the condition specified in a callback function.
@param ― predicate A function that accepts up to three arguments. The filter method calls the predicate function one time for each element in the array.
@param ― thisArg An object to which the this keyword can refer in the predicate function. If thisArg is omitted, undefined is used as the this value.
filter((
t: number
t) =>
now: number
now-
t: number
t<60_000);
returnthis.#failures.
Array<number>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
Custom rule for when a closed circuit opens; replaces failureRatio, minimumThroughput and the sampling window
(consecutiveFailures, if set, still applies too).
breakDuration (default 5 s) is how long the circuit stays open. For a break that grows while the dependency stays down, use breakDurationGenerator. It receives the window metrics (total, failureCount, failureRate), halfOpenAttempts (failed half-open rounds in a row) and context:
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
CircuitBreakerOptions<any>.consecutiveFailures?: number |undefined
Break after this many failures in a row (a success resets the count). Simple and good for low traffic.
When set without failureRatio, the ratio check is off and only this rule applies.
CircuitBreakerManualControl holds circuits open (isolated) or closes them, for example from an admin endpoint during an incident. One control can drive several breakers.
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
ResiliencePipelineBuilder,
classCircuitBreakerManualControl
Manually isolate (hold open) or close one or more circuit breakers, e.g. from an admin endpoint or a health check.
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
Holds the circuits isolated until every isolation is released (stacking) or close() is called.
Resolves to the release function of this isolation; releasing twice, or after close(), does nothing.
Holds the circuits isolated until every isolation is released (stacking) or close() is called.
Resolves to the release function of this isolation; releasing twice, or after close(), does nothing.
isolate();
await
constreleaseDeploy: () =>Promise<void>
releaseDeploy(); // still isolated: the incident hold remains
Closes the circuits now, dropping every outstanding isolation.
close(); // closes at once and drops every outstanding hold
Isolations stack: the circuit stays isolated until every isolate() has been released, or close() is called. Releasing twice does nothing. While isolated, trip() and states adopted from sharedCircuitState are ignored.
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
ResiliencePipelineBuilder,
classCircuitBreakerStateProvider
Reads the state and window metrics of a single circuit breaker (health checks, dashboards, persistence).
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
A state provider belongs to one breaker; attaching it to a second one throws. getStrategy() takes the strategy’s name (default 'CircuitBreaker') or its class name. The registry lists every breaker with registry.circuitBreakers().
Serverless functions and restarts lose in-memory state. Save stateProvider.snapshot() and pass it back as initialState. The snapshot includes the rolling window, so the failure history survives too.
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
CircuitBreakerOptions<any>.consecutiveFailures?: number |undefined
Break after this many failures in a row (a success resets the count). Simple and good for low traffic.
When set without failureRatio, the ratio check is off and only this rule applies.
Background behaviour plugged into the breaker, e.g. circuitHealthCheck({ check, interval }) or
sharedCircuitState({ store, key }) from this package. Kept out of the core breaker so you only bundle what you use.
Probes the dependency in the background while the circuit is closed; a failing probe opens it (opossum's healthCheck).
addCircuitBreaker({ extensions: [circuitHealthCheck({ check: () => db.ping(), interval: '10s' })] })
Shares the breaker's state with other instances (servers, processes) through a store, e.g. RedisCircuitStateStore:
one instance seeing the dependency fail opens the circuit for all of them.
addCircuitBreaker({ extensions: [sharedCircuitState({ store, key: 'payments' })] })
Stops background work (health checks, store sync timers). Later executions fail.
dispose();
circuitHealthCheck probes the dependency every interval while the circuit is closed. A check that throws, rejects, returns false or takes longer than timeout opens the circuit for its break duration (reported as OnHealthCheckFailed). Its timers don’t keep the process alive.
Option
Type
Default
check
(signal: AbortSignal) => unknown (or a promise)
required
interval
Duration
required
timeout
Duration
interval
sharedCircuitState syncs the state with other instances through a CircuitStateStore: one instance seeing the dependency fail opens the circuit for all of them. It writes on every local state change and reads at start and every syncInterval. The newest updatedAt wins. The rolling window stays local: each instance judges its own traffic.
Option
Type
Default
store
CircuitStateStore (get(key), set(key, snapshot))
required
key
string, one per logical breaker
required
syncInterval
Duration
'5s'
Stores: MemoryCircuitStateStore (one process, tests) and RedisCircuitStateStore from resilience-pipeline/redis (see Multi-instance with Redis). A failing store never fails calls; it is reported as OnCircuitStoreError.
Opened by the rule, a failed probe, trip(), a health check (isManual: false) or isolated (isManual: true, breakDuration: Infinity).
OnCircuitClosed
onClosed
Closed after healthy probes (isManual: false), or by reset() / manual control (isManual: true).
OnCircuitHalfOpened
onHalfOpened
The first call after the break.
OnCircuitRejected
onRejected
Every call refused while open, half-open (slots full) or isolated.
OnHalfOpenProbeTimedOut
none
A probe ran longer than halfOpenMaxWait.
OnHealthCheckFailed
none
A circuitHealthCheck failed.
OnCircuitStateSynced
none
sharedCircuitState adopted a newer remote state.
OnCircuitStoreError
none
The shared store threw.
Error
code
HTTP
Notes
BrokenCircuitError
CIRCUIT_OPEN
503
retryAfter: ms until a probe is allowed (0 while half-open slots are taken). cause: the last failure’s error.
IsolatedCircuitError
CIRCUIT_ISOLATED
503
Extends BrokenCircuitError; no retryAfter.
Both are rejections (isRejection(e) is true, guard: isBrokenCircuitError(e)): retry never retries them, other breakers don’t count them, and the default fallback handles them. With typed errors, Outcome.match needs CIRCUIT_OPEN and CIRCUIT_ISOLATED branches.