Circuit Breaker Pattern: Stop Cascading Failures Fast
The circuit breaker pattern protects a microservices system by cutting off calls to a service that is failing, so one slow dependency cannot drag the whole application down with it. It works like the fuse box in your home: when something goes wrong, it trips, protects everything else, and lets you restore power once the fault is fixed.
If you build or run distributed systems, you will meet this pattern sooner or later, usually at 2 a.m. during an outage. This guide explains the circuit breaker pattern in plain language, with diagrams, a working configuration, tuning advice and the mistakes I see most often.
Table of Contents
- Why microservices need the circuit breaker pattern
- The availability maths nobody warns you about
- How one slow service causes a cascading failure
- The three states of the circuit breaker pattern: Closed, Open and Half-Open
- How the circuit breaker pattern handles every request
- The settings that matter (with example)
- Where it fits in a production architecture
- Common circuit breaker pattern mistakes
- Frequently asked questions
Why microservices need the circuit breaker pattern
In a monolith, a function call either works or throws an error in microseconds. In microservices, every call crosses a network. Networks drop packets, services get overloaded, databases lock up, and deployments go wrong. Calls do not just fail; they often hang.
A hanging call is far more dangerous than a failed one. A failure returns quickly and frees the thread. A hang holds on to a thread, a connection and some memory for as long as the timeout lasts. Multiply that by hundreds of requests per second and your healthy service runs out of resources while it waits for an unhealthy one.
The circuit breaker fixes this with one simple idea: if a dependency is clearly struggling, stop asking it. Fail instantly, protect your own resources, and try again later.
The availability maths nobody warns you about
Here is a number that surprises many teams. A service with 99.99% availability (“four nines”) is still down for about 52 minutes a year. That sounds perfectly acceptable. Now imagine 50 such services working together. Add up their individual downtime and you get roughly 2,600 minutes, or about 44 hours a year, scattered across different days, and that is when every single service is performing well.
Real services are rarely five nines. So in a large microservice estate, something is almost always failing somewhere. The question is not “how do we prevent every failure?” but “how do we stop a failure from spreading?” That is exactly the job of the circuit breaker pattern.
How one slow service causes a cascading failure
Imagine an online store. The storefront (Service A) calls the order service (B), which calls the inventory service (C), which calls a warehouse stock API (D). One afternoon D becomes slow, taking 30 seconds to answer instead of a fraction of a second.
- C’s threads pile up waiting for D.
- C stops answering B quickly, so B’s threads pile up too.
- The same happens at A, and finally the user-facing layer.
- Even when D recovers, the backlog of queued requests can knock it straight over again.
This is a cascading failure. The original problem was one slow service; the final outcome is a full outage. The diagram below shows the difference a breaker makes.

The three states of the circuit breaker pattern: Closed, Open and Half-Open
A circuit breaker sits between the caller and the remote service as a small proxy. It is always in one of three states.

Closed: business as usual
Requests flow through to the service. The breaker quietly counts successes, failures and slow calls in a sliding window. As long as the failure rate stays under your threshold, nothing changes.
Open: stop calling, fail fast
When the failure rate crosses the threshold (say 50% of the last 20 calls), the breaker trips. For a set period, every request is rejected immediately, with no network call at all. Callers get an instant error or a fallback response. This protects your threads and gives the struggling service breathing room.
Half-Open: carefully testing recovery
After the wait time passes (say 30 seconds), the breaker lets a few trial requests through. If they succeed, the service is assumed healthy and the breaker closes. If they fail, it opens again and the wait starts over. Recovery is automatic, with no human needed.
How the circuit breaker pattern handles every request
The flowchart below follows one request through the breaker. It is a handy reference when you are explaining the behaviour to a teammate or debugging why traffic is being rejected.

The settings that matter (with example)
There are no universal values. Good settings come from your own traffic and your service’s behaviour. These are the knobs you will tune:
- Failure rate threshold: the percentage of failed calls that trips the breaker.
- Slow call threshold: how long counts as “too slow”. If a service normally answers in around 150 ms, calls beyond 300 ms may deserve to count as failures.
- Sliding window size: how many recent calls (or seconds) are evaluated.
- Minimum calls: the smallest sample before the breaker is allowed to judge. This prevents tripping on 1 failure out of 2 calls.
- Wait duration in open state: how long to stay open before testing recovery.
- Permitted calls in half-open: how many trial requests are allowed.
Here is a sample configuration using Resilience4j with Spring Boot, one of the most widely used options in the Java world:
resilience4j:
circuitbreaker:
instances:
inventoryService:
slidingWindowType: COUNT_BASED
slidingWindowSize: 20
minimumNumberOfCalls: 10
failureRateThreshold: 50
slowCallDurationThreshold: 300ms
slowCallRateThreshold: 75
waitDurationInOpenState: 30s
permittedNumberOfCallsInHalfOpenState: 3
automaticTransitionFromOpenToHalfOpenEnabled: true
timelimiter:
instances:
inventoryService:
timeoutDuration: 500ms
@CircuitBreaker(name = "inventoryService", fallbackMethod = "stockFromCache")
public StockLevel checkStock(String sku) {
return inventoryClient.getStock(sku);
}
private StockLevel stockFromCache(String sku, Throwable t) {
return stockCache.lastKnown(sku); // stale but useful beats an error page
}
Not using Java? The same idea exists everywhere: Polly for .NET, opossum for Node.js, gobreaker for Go, and service meshes such as Istio or Envoy, which can apply circuit breaking at the network layer without touching your code.
Where it fits in a production architecture
A circuit breaker works best as part of a team, not on its own. In production you normally combine it with:
- Timeouts: every remote call needs one. Without a timeout, the breaker never learns the call was slow.
- Retries with backoff and jitter: for brief glitches, but never retry into an open breaker.
- Bulkheads: separate thread or connection pools per dependency, so one bad service cannot use up everything.
- Fallbacks: cached data, sensible defaults, or queuing the work for later.
- Observability: metrics and alerts on state changes, failure rate and latency.

Choose your fallback wisely
Failing fast is better than waiting, but a good fallback is better still. A product page can show cached prices. A recommendations panel can simply hide itself. A payment request should never be silently faked; return a clear error or queue it safely. Decide per dependency what “degraded but useful” looks like for your users.
Common circuit breaker pattern mistakes
- No timeout on the call. The breaker can only react to what it sees. Set a timeout shorter than your caller’s own timeout.
- Counting the wrong errors. A 404 or a validation error is not an outage. Count timeouts, connection errors and 5xx responses; ignore business errors.
- Tripping on tiny samples. Always set a minimum number of calls.
- One breaker for everything. Use one per dependency (or even per endpoint), so a failing report service does not block checkout.
- Retry storms. Aggressive retries against a recovering service can finish it off. Use backoff and let the breaker gate retries.
- Setting it and forgetting it. Review settings against real traffic. Put breaker state on a dashboard and alert when one stays open.
- Never testing it. Inject failures in staging, for example with chaos experiments, and confirm that the breaker opens, the fallback works and the system recovers.
Key takeaways
- Failures in distributed systems are normal; spreading is the real danger.
- The circuit breaker pattern trades a few fast, controlled failures for protection against slow, system-wide ones.
- Closed lets traffic through, Open blocks it, Half-Open tests recovery.
- Pair it with timeouts, bulkheads, fallbacks and good monitoring.
- Tune it using real traffic data, and test it before you need it.
Frequently asked questions
What is the circuit breaker pattern in microservices?
It is a resilience pattern where a proxy monitors calls to a remote service and stops sending requests when too many fail or run slowly. This prevents resource exhaustion and cascading failures, and it restores traffic automatically once the service recovers.
What are the three states of a circuit breaker?
Closed (normal operation, failures counted), Open (calls blocked and rejected immediately) and Half-Open (a limited number of trial calls test whether the service has recovered).
What is the difference between a retry and a circuit breaker?
A retry tries again, hoping a temporary glitch has passed. A circuit breaker decides when to stop trying. They work well together: retry for brief blips, and let the breaker block calls when the problem is persistent.
How do I choose the failure threshold and timeout values?
Start from observed behaviour: normal latency, typical error rate and recovery time. Set slow-call limits slightly above normal response times, require a minimum sample size, and tune after watching the breaker in real traffic.
Which libraries implement circuit breakers?
Resilience4j for Java and Spring Boot (the successor to Netflix Hystrix, which is in maintenance mode), Polly for .NET, opossum for Node.js and gobreaker for Go. Service meshes like Istio and Envoy provide circuit breaking at the infrastructure level.
Does a circuit breaker replace monitoring?
No. It reacts automatically, but you still need dashboards and alerts to learn why a service failed and to keep your thresholds sensible.
Further reading
- Martin Fowler: Circuit Breaker, the classic short introduction to the pattern.
- Azure Architecture Center: Circuit Breaker pattern, guidance on when to use it and its trade-offs.
- Resilience4j CircuitBreaker documentation, the full configuration reference.
- Design Patterns for Microservices: Circuit Breaker Pattern (Geek Culture on Medium), another beginner-friendly take on the same topic.
Final thoughts
You cannot stop services from failing, but you can decide how much damage a failure is allowed to do. A well-configured circuit breaker pattern is one of the cheapest and most effective ways to keep a microservices system standing when something inevitably breaks.
If you found this useful, explore more guides in the Technology & Innovation section, and share it with a teammate who is about to design their next service-to-service call.

Leave a Reply