Design Patterns Circuit Breaker

The Circuit Breaker pattern stops an application from repeatedly calling a service that keeps failing. After enough failures, the breaker opens and rejects calls immediately. Time passes, a test call checks recovery, and normal traffic resumes when the service heals.

The Real-World Analogy

An electrical breaker in a home panel trips when too much current flows. The trip protects wiring from damage. After the problem gets fixed, someone resets the breaker and power returns. Software breakers protect systems from a similar overload of failing requests.

Problem Without a Breaker

Checkout ──▶ Payment Service (down, each call waits 30 seconds)

100 users × 30 seconds of waiting = threads pile up
Checkout runs out of threads and crashes too
One broken service drags the whole system down.

Solution With a Breaker

Checkout ──▶ ┌─────────────────┐ ──▶ Payment Service
             │ Circuit Breaker │
             └─────────────────┘
   Failures pile up → breaker opens → Checkout gets an instant answer
   ("Payment is busy, try again soon") instead of a long wait.

The Three States

                failures reach limit
   ┌────────┐ ───────────────────────▶ ┌────────┐
   │ CLOSED │                          │  OPEN  │
   │ calls  │                          │ calls  │
   │ pass   │ ◀─────────┐              │ blocked│
   └────────┘           │              └───┬────┘
        ▲               │ test call        │ wait time ends
        │ success       │ succeeds         ▼
        │            ┌──┴───────────┐
        └─────────── │  HALF-OPEN   │
                     │ one test call│ ── test call fails ──▶ back to OPEN
                     └──────────────┘

Closed

Calls flow normally. The breaker counts failures.

Open

Calls fail instantly without reaching the service. A timer runs.

Half-Open

The breaker allows a small number of test calls. Success closes the breaker, and failure reopens it.

Code Example

class CircuitBreaker {
    private String state = "CLOSED";
    private int failures = 0;
    private int limit = 3;
    private long openedAt = 0;
    private long waitMillis = 10000;

    Response call(Service service, Request request) {
        if (state.equals("OPEN")) {
            if (now() - openedAt > waitMillis) {
                state = "HALF_OPEN";                  // try again
            } else {
                return Response.fallback("Service busy, try later");
            }
        }
        try {
            Response r = service.send(request);
            onSuccess();
            return r;
        } catch (Exception e) {
            onFailure();
            return Response.fallback("Service busy, try later");
        }
    }

    private void onSuccess() {
        failures = 0;
        state = "CLOSED";
    }

    private void onFailure() {
        failures = failures + 1;
        if (failures >= limit || state.equals("HALF_OPEN")) {
            state = "OPEN";
            openedAt = now();
        }
    }
}

Fallback Strategies

StrategyExample
Cached dataShow the last known product price
Default valueDisplay an empty recommendation list
Friendly message"Reviews are loading slowly, check back soon"
Alternative serviceRoute to a backup provider

Tuning the Breaker

  • Failure limit: too low trips on harmless blips, and too high reacts late.
  • Open duration: short waits retry too early, and long waits delay recovery.
  • Timeout per call: always set one, since waiting forever defeats the purpose.

Related Patterns

State describes the three breaker modes cleanly. Proxy often wraps the remote call. Null Object supplies safe fallback answers. API Gateways commonly embed breakers for every service they reach.

Advantages and Disadvantages

AdvantagesDisadvantages
Stops cascading failuresNeeds careful tuning
Fast responses during outagesFallback design takes thought
Gives failing services room to recoverAdds monitoring needs

Step-by-Step Walkthrough

Walk through a failing service. Three calls fail in a row, and onFailure() pushes the failure count to the limit. The breaker flips to OPEN and records the time. Calls during the next ten seconds return the fallback message immediately.

After the wait ends, the next call moves the breaker to HALF_OPEN and reaches the service. A success resets the counter and closes the breaker. Failure reopens it and restarts the timer.

Monitoring the Breaker

  • Record every state change with a timestamp.
  • Track failure rates per service on a dashboard.
  • Alert the team when a breaker stays open for long periods.

Common Mistakes

  • Counting expected errors, such as "not found," as failures.
  • Skipping a fallback, which leaves users with raw error pages.
  • Sharing one breaker between unrelated services, which punishes healthy ones.

Plain-Words Summary

Resilience stories often begin with a small outage that spreads. A slow payment service holds threads, the web server runs out of capacity, and the whole site goes down. Failing fast, a circuit breaker cuts that chain and giving the struggling service time to recover. Adding one around every remote call is a habit worth building early in any project.

Key Takeaways

  • A circuit breaker blocks calls to a failing service for a short time.
  • The three states are closed, open, and half-open.
  • Fallbacks keep users informed during outages.
  • Tune limits and timers against real traffic.