Circuit Breaker
Stop calling a failing dependency for a while, so its failure doesn't become yours.
To an executive
One struggling supplier or internal service can drag down everything that relies on it. Cutting it off quickly keeps customers served and limits the damage of an outage.
To an engineer
Wrap calls to a dependency so that after repeated failures they fail fast, then trial calls test recovery. Define a fallback and alert on state changes.
The idea
An electrical circuit breaker cuts the power when current gets dangerous, protecting the wiring behind it. Michael Nygard applied the same idea to calls between software components in Release It!. A breaker wraps calls to a dependency and watches for failures. When failures pass a threshold, it opens, and further calls fail immediately without touching the dependency. After a cool-off period it goes half-open and lets a few trial calls through. If they succeed, it closes again; if not, it opens for another period.
Its purpose is to stop cascading failures. A dependency that hangs is often worse than one that fails, because every waiting call holds a thread, a connection, or memory in the caller. Enough of them and the caller stops responding too, then its own callers, until a single slow service has stalled the whole system.
Why it works
Failing fast frees resources. An open breaker answers in microseconds instead of waiting for a timeout, so the caller keeps its threads and connections for work that can succeed.
It gives the dependency room to recover. A struggling service hit by constant retries rarely recovers. Stopping the traffic, then testing it gently, lets it get back on its feet.
It makes failure explicit. Callers get a clear "unavailable" signal they can handle with a fallback, instead of an ambiguous slow response.
Where it applies
- Calls to remote services that may be slow or unavailable, especially third-party APIs outside your control.
- Non-critical features where a degraded answer is better than none: recommendations, personalisation, enrichment, analytics.
- Shared resources such as databases or caches that many callers depend on, where one overloaded resource could take everything down.
- Incident response, as a lever operators can trip by hand to shed load from a struggling component.
How to apply
- Set timeouts first. A breaker counts failures; without timeouts, a hung call never counts as one. Every remote call needs a timeout shorter than its caller's own deadline.
- Decide what counts as failure. Timeouts, connection errors, and server errors usually should. Client errors, such as invalid input, usually should not, or a single bad request could trip the breaker for everyone.
- Design the fallback. Decide what callers do when the breaker is open: serve cached data, return a default, queue the work for later, or tell the user honestly that a feature is unavailable. This is a product decision as much as a technical one.
- Tune thresholds and timings. Choose how many failures in what window trip the breaker, how long it stays open, and how many trial calls it allows. Start conservatively and adjust from production data.
- Use one breaker per dependency. Combine breakers with bulkheads, so that one failing dependency cannot use up resources shared with others.
- Make state visible. Emit metrics and events on every state change, show them on dashboards, alert on them, and rehearse them in game days or chaos experiments.
Example scenario
During a holiday sale, an online shop's external fraud-check API slowed from 200 milliseconds to 30 seconds. Checkout threads queued up waiting for it, the thread pool ran out, and within minutes the entire site stopped responding, including pages that had nothing to do with fraud checks.
Afterwards the team added a two-second timeout and a circuit breaker around the fraud check. When it opens, orders under a set value are accepted and queued for review later, and larger ones show a "we'll confirm shortly" message. The next fraud-API outage tripped the breaker within seconds. Customers kept checking out, and the operations team saw the open breaker on their dashboard before anyone reported a problem.
Questions to ask
- What happens to callers when this dependency hangs rather than fails?
- What is the fallback when the breaker is open, and is it acceptable to users?
- Which failures should count towards tripping the breaker, and which should not?
- How long should it stay open, and how will it test that the dependency has recovered?
- Do we monitor, alert on, and rehearse breaker state changes?
When not to use it
- In-process or local calls. Calls to memory or local libraries don't fail in the ways breakers protect against; a breaker only adds overhead.
- As a substitute for error handling. A breaker contains failures of a dependency. It does not replace validating input or handling business errors.
- When the platform already does it. Service meshes, load balancers, and message queues with dead-letter handling may already provide equivalent protection. Two layers of breakers with different settings are hard to reason about.
How it misleads you
Breakers tuned too aggressively cause self-inflicted outages: a brief blip trips them, and a healthy dependency is cut off for the whole cool-off period. Breakers tuned too loosely never trip and give a false sense of safety.
A breaker without a sensible fallback only changes a slow error into a fast one. The protection comes from the combination of timeout, breaker, and a deliberate degraded mode.
In the wild
Further reading
- Release It! Design and Deploy Production-Ready Software (2nd ed.)Michael Nygard · Book · 2018(opens in a new tab)
- Circuit BreakerMartin Fowler · Article · 2014(opens in a new tab)
- Circuit Breaker patternMicrosoft Azure Architecture Center · Website(opens in a new tab)
Last reviewed · Suggest an improvement