CMD Guide
HomeSystem DesignMicroservices Patterns

Circuit Breaker Pattern An Example

Let’s implement a basic Circuit Breaker in Java to illustrate the core algorithm. We won’t use any external libraries – just a simple class to demonstrate the state logic:

public class CircuitBreaker { private enum State { CLOSED, OPEN, HALF_OPEN } private State state = State.CLOSED; private int failureCount = 0; private final int failureThreshold; private final long openTimeout; // how long to stay open before trying half-open private long lastFailureTime = 0; public CircuitBreaker(int failureThreshold, long openTimeout) { this.failureThreshold = failureThreshold; this.openTimeout = openTimeout; } public synchronized <T> T call(Callable<T> remoteCall) throws Exception { // 1. If breaker is OPEN, check if timeout has passed to allow a half-open trial if (state == State.OPEN) { long timeSinceFailure = System.currentTimeMillis() - lastFailureTime; if (timeSinceFailure < openTimeout) { // Still within open timeout, reject the call fast throw new IllegalStateException("Circuit is OPEN. Failing fast without calling remote service."); } else { // Timeout passed, move to half-open and allow a trial call state = State.HALF_OPEN; } } // 2. Try to invoke the remote call (allowed if state is CLOSED or HALF_OPEN) try { T result = remoteCall.call(); // Call succeeded. Reset failure count and close the circuit (if it was half-open, now fully close it). failureCount = 0; state = State.CLOSED; return result; } catch (Exception e) { // Call failed. Increase the failure count. failureCount++; lastFailureTime = System.currentTimeMillis(); if (failureCount >= failureThreshold) { // Too many failures, trip the circuit to OPEN state. state = State.OPEN; } throw e; // Propagate the exception (or could return a fallback here) } } }

One simplification here is a trap if you copy it: synchronized wraps the remote call itself, so while one call is in flight every other caller — even ones that should fail fast against an OPEN breaker — blocks at the lock before it can so much as check the state. The breaker becomes a serializer: maximum throughput through it is 1/latency (12.5 req/s at 80 ms calls, and near zero while one call hangs toward a timeout) — it re-creates exactly the thread pile-up the pattern exists to prevent. Production implementations hold a lock (or use atomics — e.g. an AtomicReference for state plus LongAdder counters) only for the state check and the outcome update, and execute the remote call outside any lock; Resilience4j's state machine works exactly this way.

In the code above, CircuitBreaker tracks the number of failures and the current state. The call method wraps the execution of a remote operation (passed as a Callable<T>). Here’s how it works:

  1. Before calling the remote service, it checks the state. If the circuit is OPEN, the code checks if the open timeout has elapsed. If not (meaning it's too soon to retry), it fails fast by throwing an exception (IllegalStateException in this case) instead of calling the remote service. If the timeout has elapsed, the breaker moves to HALF_OPEN state, allowing one trial call to proceed.

  2. Executing the call: If the state is Closed or Half-Open, it attempts the remoteCall. This is where your actual remote service logic would run.

  3. After the call returns: If the call succeeds, we reset the failure counter and set the state to CLOSED. (In Half-Open, a success means the service is back, so we fully close the circuit again. In Closed, a success just keeps it closed and can reset any past failure count.) If the call throws an exception or times out, we increment the failure count and record the time of failure. If the failures have reached the failureThreshold, the circuit switches to OPEN (tripped). The exception is rethrown to the caller – in a real system, the caller might catch this and fall back to some default behavior.

Using this CircuitBreaker is straightforward. For example:

CircuitBreaker cb = new CircuitBreaker(3, 10000); // trip after 3 failures, 10s timeout try { String data = cb.call(() -> unreliableService.getData()); // use data... } catch (Exception e) { // Handle fallback logic because service call failed or circuit is open useCachedData(); }

In this example, if unreliableService.getData() fails 3 times in a row, the circuit breaker will open. Further attempts within 10 seconds will immediately throw an exception without calling getData() at all – the circuit breaker is preventing more failures. After 10 seconds, the next call will be allowed to try the service again (half-open). If that next call succeeds, the circuit closes and things go back to normal. If it fails, the circuit re-opens and will block calls for another 10 seconds.

This is a simplistic implementation to demonstrate the concept. In production, a circuit breaker might be more sophisticated – locking only state transitions instead of the whole call (this version is thread-safe, but by holding the lock across the remote call it serializes every caller, as flagged above), using a rolling window of failure metrics, or integrating with monitoring systems – but the core idea is the same.

Interactive walkthrough

Predict the next step in the circuit-breaker scenario.

What the simple example omits

The code above illustrates the state machine, but a production breaker adds three things:

When NOT to wrap a call in a breaker

Tuning the knobs

Three numbers control behavior:

Pairing with retries and bulkheads

A breaker is not a retry policy. Retries recover from transient failures; breakers stop sending load during sustained failures. Use them together: retry a call a small number of times with backoff, and only count the final failure toward the breaker. Combine with a bulkhead so that while the breaker is open, the caller's threads are not tied up waiting.

Takeaways

The threshold decision the example glosses over: count vs rate, and where they cross

The new CircuitBreaker(3, 10000) above trips on an absolute count — 3 failures. That is the right choice at low traffic and a latent outage at high traffic, and the switchover point is computable, not a matter of taste. Two threshold styles compete:

Why a fixed count breaks at high volume. A count threshold C is only meaningful relative to how many calls flow through the window. The normal-noise failures in one window are baseline_error_rate × λ × window, where λ is requests/second. (Careful: the example's 10000 ms is its open-state cooldown, not a failure-counting window — the example has no window, so pick the observation window explicitly.) Take a 10 s observation window, a benign baseline error rate of 1%, and a slightly more forgiving C = 5:

The crossover. A fixed count C stops being safe the moment normal-noise failures per window reach it: baseline × λ × window ≥ C. Solving for the traffic where these numbers cross:

λ* = C / (baseline × window) = 5 / (0.01 × 10) = 50 req/s

Below ~50 req/s a small absolute count is the better tool — it is simpler and reacts on the first few failures, whereas a rate window with minimumNumberOfCalls = 100 would take 100 / λ seconds just to start evaluating (20 s at 5 req/s — an eternity during an outage). Above ~50 req/s the count threshold drowns in noise and you must move to a percentage threshold with a minimum-volume floor. The number moves with your inputs — halve the baseline error rate and λ* doubles to 100 req/s, and with the example's own C = 3 it drops to 3 / (0.01 × 10) = 30 req/s — but the rule is fixed: compute C / (baseline × window); if your real traffic is above it, a count threshold will false-trip, so switch to rate.

🤖 Don't fully get this? Learn it with Claude

Stuck on Circuit Breaker Pattern An Example? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🎨 Explain it visually

Build the mental picture, not memorization.

I just read a lesson on **Circuit Breaker Pattern An Example** (System Design) and want to truly understand it. Explain Circuit Breaker Pattern An Example from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🤔 Walk me through it (interactive)

Socratic — adapts to where you're stuck.

Teach me **Circuit Breaker Pattern An Example** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧪 Quiz me & fix my gaps

Active recall exposes what you missed.

Quiz me on **Circuit Breaker Pattern An Example** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧠 Make it stick

Intuition + hook + flashcards for long-term memory.

Help me remember **Circuit Breaker Pattern An Example** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes