Circuit breaker — when to stop trying
Every call to another service can fail — network drops, the other service is overloaded, timeouts. Our first reflex is usually retry. But retrying while the target is dying adds load: failed requests get re-attempted, queues pile up, and the failure spreads to the callers. That's a cascade failure.
A circuit breaker solves it with simple logic: if the destination is proven sick, stop trying. Fail fast, wait, probe carefully, then return to normal.
The three breaker states
- CLOSED — everything normal, requests flow. What's watched: the error rate over a window (say, the last 10 requests).
- OPEN — threshold exceeded. All requests are rejected instantly without touching the sick service. This is what saves the system: no resources burned waiting for timeouts.
- HALF-OPEN — after a cooldown, the breaker allows a few probes. Consecutive successes → back to CLOSED; a failure → OPEN again.
Play with it yourself
The simulation below runs a service with a failure rate you control. Push the rate above the 60% threshold and watch the sequence: the window fills with failures → the breaker trips (OPEN) → subsequent requests are rejected instantly (hollow circles) → cooldown → HALF-OPEN → recovery, or another trip.
INTERACTIVE SIMULATION
CLOSED
traffic flows
OPEN
fail fast
HALF-OPEN
probe
← probe ok → CLOSED
trip → rejected instantly
window 10 · failed 0 · rejected 0 · total 0
Without vs with a breaker
Every request waits out its timeout (say 30 seconds). With 100 requests/sec while the service is down, some 3,000 requests are hanging at any moment — the caller's thread pool exhausts, and healthy services topple with it.
One request, the full story
A client calls service B through a breaker that is currently CLOSED.
Implementation notes
A few things decide whether a breaker is pleasant or painful in production: pick the threshold and window based on the caller's capacity (not library defaults); use different cooldowns for client errors vs infrastructure errors; make sure breaker state is exposed to monitoring — a silently OPEN breaker is an incident waiting to happen; and provide a meaningful fallback for every caller, because failing fast without a fallback just relocates the failure.
The pattern ships in nearly every stack: resilience4j (JVM), pybreaker/circuitbreaker (Python), Polly (.NET), opossum (Node). The library matters less than the threshold, cooldown, and fallback decisions that fit your system.