What Is the Circuit Breaker Pattern?

Your app calls a payment service. One day, that service gets slow: every request hangs for 30 seconds before failing. Your app keeps calling it. Threads pile up waiting, memory fills, and soon your app is down too, even though the problem was somewhere else.

A circuit breaker prevents this. Like the electrical breaker in your home, it trips when something goes wrong and stops the flow, so one failing service can't take down everything connected to it.


🎯 Quick Answer (30-Second Read)

  • A circuit breaker wraps calls to another service and watches for failures.
  • Closed: calls flow normally while failures are counted.
  • Open: after too many failures, calls fail immediately without touching the broken service.
  • Half-open: after a cool-down, a few test calls go through. Success closes the circuit, failure opens it again.
  • Pair it with timeouts, retries (carefully) and fallbacks. Popular libraries: Resilience4j (Java), Polly (.NET), pybreaker (Python). Netflix's Hystrix popularised the pattern but is now in maintenance mode.

The Problem: Cascading Failures

flowchart LR U["Users"] --> A["Checkout service"] A --> B["Payment service
🐢 slow / failing"] A --> C["Inventory service"] style B fill:#fee2e2,stroke:#ef4444

Without protection:

  1. Payment slows down.
  2. Checkout's threads all wait on payment.
  3. Checkout stops responding, even for requests that don't need payment.
  4. Services calling checkout start failing too.

That chain reaction is a cascading failure. Retrying makes it worse, because a struggling service now gets more traffic.


The Three States

stateDiagram-v2 [*] --> Closed Closed --> Open: failure rate ≥ threshold
(e.g. 50% of last 20 calls) Open --> HalfOpen: wait duration passes
(e.g. 30s) HalfOpen --> Closed: test calls succeed HalfOpen --> Open: a test call fails note right of Open Calls fail fast, fallback is used end note
State What happens to calls Purpose
Closed Pass through, results recorded Normal operation
Open Rejected instantly (or fallback returned) Give the failing service room to recover, protect your resources
Half-open A few test calls allowed Check whether the service has recovered

Fallbacks: What to Do When the Circuit Is Open

Failing fast is better than hanging, but a good fallback is better still:

Cached data
Show the last known product recommendations instead of fresh ones.
Default value
Show a generic list or "delivery estimate unavailable."
Queue for later
Accept the order and process the step when the service recovers.

This is graceful degradation: the core experience survives while a non-essential feature is temporarily reduced.


Settings You'll Tune

Setting Example Effect
Failure rate threshold 50% How bad things must be to trip
Window size Last 20 calls or last 60s How much history to judge
Minimum calls 10 Avoid tripping on 1 failure out of 2
Slow call threshold > 2s counts as failure Treat slowness like failure
Wait in open state 30s How long before testing recovery
Calls in half-open 3 How many test calls to allow

Example: Resilience4j (Java)

CircuitBreakerConfig config = CircuitBreakerConfig.custom()
    .failureRateThreshold(50)
    .slowCallDurationThreshold(Duration.ofSeconds(2))
    .slidingWindowSize(20)
    .minimumNumberOfCalls(10)
    .waitDurationInOpenState(Duration.ofSeconds(30))
    .permittedNumberOfCallsInHalfOpenState(3)
    .build();

CircuitBreaker breaker = CircuitBreaker.of("payments", config);

Supplier call = CircuitBreaker.decorateSupplier(breaker, paymentClient::charge);
String result = Try.ofSupplier(call)
    .recover(ex -> "PAYMENT_QUEUED")   // fallback
    .get();

Example: A Minimal Breaker in Python

import time

class CircuitBreaker:
    def __init__(self, max_failures=5, reset_after=30):
        self.max_failures, self.reset_after = max_failures, reset_after
        self.failures, self.opened_at = 0, None

    def call(self, fn, *args, fallback=None):
        if self.opened_at:
            if time.time() - self.opened_at < self.reset_after:
                return fallback                      # OPEN: fail fast
            self.opened_at = None                    # HALF-OPEN: try once
        try:
            result = fn(*args)
            self.failures = 0                        # success → CLOSED
            return result
        except Exception:
            self.failures += 1
            if self.failures >= self.max_failures:
                self.opened_at = time.time()         # trip → OPEN
            return fallback

This sketch counts consecutive failures. Production libraries use sliding windows, slow-call detection and thread safety.


Circuit Breaker vs Retry vs Timeout

Key takeaway: a timeout limits how long one call can wait. A retry handles brief glitches. A circuit breaker stops calling a service that is clearly unhealthy. Use all three together: timeout every call, retry a little with backoff, and let the breaker stop retries from hammering a dead service.

Frequently Asked Questions

What is the half-open state in a circuit breaker?

After the circuit has been open for a set time, it moves to half-open and lets a small number of test calls through. If they succeed, the service is considered healthy and the circuit closes. If any fail, it opens again and waits another cool-down period.

Is Hystrix still used?

Netflix Hystrix made the circuit breaker pattern popular in microservices, but it has been in maintenance mode since 2018. Netflix recommended alternatives such as Resilience4j for new projects, and service meshes like Istio also offer circuit breaking.

Where should a circuit breaker live?

Usually in the calling service, around each call to an external dependency, or in infrastructure such as an API gateway or service mesh sidecar. Use separate breakers per dependency, so one failing service doesn't block calls to healthy ones.


Conclusion

The circuit breaker pattern stops cascading failures by failing fast when a dependency is unhealthy, then testing carefully for recovery. Combine it with timeouts, limited retries and sensible fallbacks, and a single slow service becomes a degraded feature instead of a full outage.


Sources

Last verified: 14 October 2026.


Related reads: Why Netflix Rarely Goes Down · Microservices Architecture Explained · Rate Limiter Explained · Why Apps Crash During High Traffic

I write about system design and how real products are built. Follow on LinkedIn or X, or invite me to speak.