The Circuit Breaker Pattern for Unreliable Third-Party APIs
6 min read · Updated Aug 5, 2026

A circuit breaker stops your pipeline from calling a third-party API that is already failing, instead of retrying it into the ground. It tracks recent failures, and once they cross a threshold, it "opens" and short-circuits every call for a cooldown period, returning a fast failure (or a fallback) instead of another slow timeout. This protects both your own pipeline, since requests stop piling up waiting on a dead dependency, and the struggling API, since it stops receiving retry traffic that makes recovery harder.
Key takeaways
- A circuit breaker has three states: closed (calls go through normally), open (calls fail immediately without hitting the API), and half-open (a single test call checks if the API has recovered).
- Backoff and circuit breakers solve adjacent but different problems. Backoff paces retries of a single request, a circuit breaker stops making new requests to a dependency already known to be down.
- Without one, a downstream outage can cascade: every incoming request piles up waiting on a timeout from a dead API, exhausting your own server’s connection pool or worker threads.
- Pick the failure threshold and cooldown deliberately, for example open after 5 failures in 30 seconds and stay open for 60 seconds, based on how expensive a false trip is versus how expensive a slow failure is.
- A circuit breaker needs a fallback path (cached data, a degraded response, a queued retry) to be worth much. Opening the circuit without one just turns a slow failure into a fast one.
The three states, and why "half-open" matters
In the closed state, everything behaves normally: calls go to the API and failures are just counted. Once failures cross a threshold, the breaker trips to open, and every call fails immediately without touching the API at all, no timeout wait, no retry, just an instant rejection. After a cooldown period, the breaker moves to half-open and lets exactly one test request through. If that succeeds, the breaker closes again and normal traffic resumes. If it fails, the breaker goes straight back to open for another cooldown. That half-open state is what stops a breaker from either hammering a still-recovering API with full traffic the instant the cooldown ends, or staying open forever on a dependency that has actually recovered.
Implementing it
The state machine is small enough to write from scratch without pulling in a library, which also makes it easier to reason about when something goes wrong at 2 a.m.
class CircuitBreaker {
constructor({ failureThreshold = 5, cooldownMs = 60000 } = {}) {
this.failureThreshold = failureThreshold;
this.cooldownMs = cooldownMs;
this.state = 'closed';
this.failureCount = 0;
this.openedAt = null;
}
async call(fn, fallback) {
if (this.state === 'open') {
if (Date.now() - this.openedAt < this.cooldownMs) {
return fallback ? fallback() : Promise.reject(new Error('Circuit open'));
}
this.state = 'half-open';
}
try {
const result = await fn();
this.onSuccess();
return result;
} catch (err) {
this.onFailure();
if (fallback) return fallback();
throw err;
}
}
onSuccess() {
this.failureCount = 0;
this.state = 'closed';
}
onFailure() {
this.failureCount++;
if (this.state === 'half-open' || this.failureCount >= this.failureThreshold) {
this.state = 'open';
this.openedAt = Date.now();
}
}
}
The checkout outage that had nothing to do with checkout
In February 2022, at a logistics company I automated for, a shipping-rate API went down for about 20 minutes during a partial outage on their end. Without a circuit breaker, order-checkout requests kept queueing behind 30-second timeouts waiting on that dead API, and the checkout service’s worker pool, capped at 50 connections, filled up completely within about six minutes. Checkout went down entirely, for every order, including the majority that would not have touched shipping rates at all if the request had failed fast. We added a circuit breaker around that specific dependency afterward. The next outage on that same shipping-rate API, in July of that year, degraded rate accuracy for about 20 minutes. Checkout itself never went down.
Which state you are in, and what happens in each
| State | Calls to the API | What changes the state |
|---|---|---|
| Closed | Allowed normally | Failures reach the threshold within the tracking window, moves to open |
| Open | Rejected immediately, API is never called | Cooldown timer expires, moves to half-open |
| Half-open | Exactly one trial call allowed | Success moves to closed, any failure moves back to open |

I think circuit breakers are one of the most under-used patterns in n8n and Zapier-style automation builds, specifically because visual workflow tools make it easy to wire up "call API, on error retry" and much harder to wire up "call API, but only if it has not failed five times in the last minute." That asymmetry means most no-code pipelines have retry logic and approximately none have breaker logic, right up until a dependency has a genuinely bad day and takes something unrelated down with it.
Netflix popularized this pattern at real scale with Hystrix, a resilience library open-sourced in 2012 specifically to stop one failing dependency, out of the dozens a single API call could touch internally, from cascading into a platform-wide outage. Hystrix itself is in maintenance mode now, replaced by newer resilience libraries, but the state machine it made mainstream (closed, open, half-open) is still the pattern almost every modern implementation follows.
“A circuit breaker does not make a dependency more reliable. It makes your own system stop pretending an unreliable dependency is fine.”
Frequently asked questions
Frequently asked questions
What is the circuit breaker pattern?
A resilience pattern that stops a pipeline from calling a dependency that has already failed repeatedly. After a failure threshold is crossed, the breaker "opens" and rejects calls immediately for a cooldown period, instead of letting every request wait out a slow timeout against a dependency that is not going to respond.
What is the difference between a circuit breaker and retry or backoff logic?
Backoff paces how and when a single failed request gets retried. A circuit breaker operates at a higher level: it decides whether to attempt any new requests to a dependency at all, based on that dependency’s recent failure history. Most production pipelines use both together.
What are the three states of a circuit breaker?
Closed (normal operation, calls go through), open (calls are rejected immediately without hitting the dependency), and half-open (a single trial call is allowed after the cooldown, to check whether the dependency has recovered).
How do I choose a failure threshold?
Base it on the dependency’s normal baseline error rate, not zero. If an API typically runs a 1 to 2% error rate under healthy conditions, a threshold like five failures within a short rolling window is a reasonable signal something changed, without tripping on ordinary noise.
Does n8n have a built-in circuit breaker?
No. You have to build the state yourself, typically by storing a failure count and an "opened at" timestamp in a data table or Redis, then checking that state with an IF node before the HTTP Request node runs.
What happens when the circuit is open?
Every call fails immediately without contacting the dependency at all, until the cooldown period expires and the breaker moves to half-open to test recovery. A well-designed breaker pairs this with a fallback, cached data or a degraded response, rather than just failing fast with nothing to show for it.