What Is the Circuit Breaker Pattern in Software?
The circuit breaker pattern stops a service from hammering a failing dependency, failing fast instead and giving the downstream system room to recover.
The circuit breaker pattern stops a service from repeatedly calling a dependency that’s already failing, tripping open after enough errors and rejecting calls immediately instead of waiting on timeouts. It borrows its name and behavior directly from the electrical circuit breaker: when current draw crosses a threshold, the breaker trips and cuts the circuit before something burns out, rather than letting the fault keep drawing power.
The problem: cascading failure
In a distributed system, services call other services. If Service B starts failing — overloaded, crashed, or just slow — every request Service A sends to it still has to wait out a timeout before giving up. Under load, A’s own worker threads or connection pool fill up with requests stuck waiting on B, and A starts failing too, even though A’s own code is fine. The failure cascades outward, and what should have been an isolated problem with B takes down everything that depends on it.
This is a common cause of the kind of outage that starts small and spreads — see what an SLA, SLO, and SLI actually measure for how teams track the blast radius of incidents like this. A circuit breaker is one of the primary tools for preventing that spread in the first place.
Three states
A circuit breaker moves between three states based on recent call outcomes:
- Closed — the normal state. Calls pass through to the dependency, and the breaker counts successes and failures.
- Open — once failures cross a configured threshold (e.g. 50% error rate over the last 20 calls, or 10 consecutive failures), the breaker trips open. While open, calls fail immediately without even attempting the network request — no waiting on a timeout, no adding load to an already-struggling dependency.
- Half-open — after a cooldown period, the breaker allows a small number of trial requests through. If they succeed, the breaker closes again and traffic resumes normally. If they fail, it reopens and the cooldown restarts.
CLOSED --(failure threshold exceeded)--> OPEN
OPEN --(cooldown elapsed)--> HALF-OPEN
HALF-OPEN --(trial succeeds)--> CLOSED
HALF-OPEN --(trial fails)--> OPEN
The half-open state is what makes this self-healing rather than a one-way kill switch: the breaker keeps probing the dependency at a low rate and recovers automatically once it’s healthy again, without a human having to flip it back on.
Fail fast, then fail gracefully
Tripping the breaker only solves half the problem — the caller still needs to do something useful when calls are being rejected. Typical strategies, often combined:
- Return a cached or default value instead of the live result, if slightly stale data is acceptable.
- Degrade the feature — show a page without the “recommended for you” widget rather than failing the whole page load because the recommendation service is down.
- Queue and retry later for operations that can be deferred, like a non-urgent email.
- Fail the request explicitly with a clear error, if there’s genuinely no acceptable fallback — this is still far better than hanging until a client-side timeout.
This is the same failure-handling instinct behind idempotency in retry logic: assume calls will fail sometimes, and design what happens next rather than treating failure as exceptional.
Where it fits relative to other resilience patterns
Circuit breakers are usually deployed alongside, not instead of, a few other patterns:
- Timeouts bound how long a single call waits before giving up. A circuit breaker without timeouts is much less effective, since slow-but-not-yet-failed calls can still exhaust resources before the breaker trips.
- Retries with backoff handle transient blips. Retrying against an already-open circuit breaker is pointless — the breaker should short-circuit retries too, which is part of why libraries usually bundle both.
- Bulkheads isolate resource pools (connection pools, thread pools) per dependency, so one slow dependency can’t starve resources needed for calls to a healthy one.
- Rate limiting protects a service from being overwhelmed by callers; a circuit breaker is the mirror image, protecting a caller from an overwhelmed dependency. See what rate limiting is for the inbound side of this.
In a service mesh, circuit breaking is often implemented at the infrastructure layer — the sidecar proxy tracks call outcomes and trips per-destination breakers — so individual services don’t need to implement the logic themselves. This is one of the concrete capabilities that pushes teams toward adopting a mesh once they have more than a handful of interdependent services, especially ones running on Kubernetes where service-to-service calls multiply quickly.
Configuring thresholds well
A circuit breaker configured too aggressively trips on normal blips and adds latency for no reason; one configured too loosely never trips before the cascading failure it was meant to prevent. Reasonable starting points: use a rolling window (last N calls or last N seconds) rather than a lifetime counter, so an old failure doesn’t count against a now-healthy dependency; and make the failure threshold and cooldown duration tunable per dependency, since a critical payment API and a non-critical analytics endpoint warrant very different tolerances. As with most reliability tuning, start conservative and adjust based on real incident data rather than guessing up front.
The takeaway
A circuit breaker trips open after a dependency starts failing, rejecting calls immediately instead of letting them queue up and time out, then probes periodically in a half-open state to detect recovery automatically. It’s a targeted fix for cascading failure — one struggling service taking down everything that calls it — and it works best paired with timeouts, bounded retries, and a real fallback for what to do when the breaker is open.
Tagged
Keep reading
Chisato · · 3 min read What Is a Runbook? Incident Response Playbooks
A runbook is a step-by-step document for handling a specific operational task or incident, turning tribal knowledge into a repeatable procedure.
Chisato · · 4 min read Kubernetes ConfigMaps vs Secrets: What's the Difference
ConfigMaps store non-sensitive configuration; Secrets store credentials with base64 encoding and tighter access controls. When to use each.
Chisato · · 4 min read What Is a NAT Gateway?
A NAT gateway lets private-subnet resources reach the internet outbound while staying unreachable from it, translating private IPs to a public one.