IntermediateSoftware Engineer

Implement a circuit breaker decorator

Build a production-grade circuit breaker as a Python decorator. It should track consecutive failures, open the circuit (raising an error immediately without calling the wrapped function) after 3 failures, transition to half-open after 30 seconds, and close again when the next call succeeds.

Why this matters

Circuit breakers prevent a slow or failing downstream service from cascading into a full system outage. Without them, threads pile up waiting for a timeout, memory exhausts, and a single dependency brings down an entire API. Every experienced backend engineer has been paged for exactly this at least once.

Before you start

Step-by-step guide

  1. 1

    Define the state machine

    The circuit breaker has three states: CLOSED (normal operation), OPEN (failing fast), and HALF_OPEN (testing recovery). Draw the state transitions on paper before writing code: failure threshold in CLOSED -> OPEN; timeout elapsed in OPEN -> HALF_OPEN; success in HALF_OPEN -> CLOSED; failure in HALF_OPEN -> OPEN.

  2. 2

    Write the CircuitBreaker class

    Create a class that holds state, failure count, and the time the circuit opened. Implement a call() method that checks state and either executes the function or raises CircuitOpenError immediately. Keep the class separate from the decorator; this makes it testable and reusable.

  3. 3

    Wrap it as a decorator

    Write the @circuit_breaker decorator that creates a CircuitBreaker instance (or accepts one as an argument) and wraps the target function. Use functools.wraps to preserve the wrapped function's name and docstring. Test that the decorator can be applied to both sync and async functions.

  4. 4

    Test all three state transitions

    Write four tests: one for normal operation, one that triggers the open state after 3 failures, one that verifies calls fail fast while open, and one that verifies recovery via the half-open state. Mock time.time() to test the 30-second timeout without actually waiting.

  5. 5

    Add a fallback parameter

    Allow the decorator to accept an optional fallback function that is called when the circuit is open instead of raising an error. This is how production circuit breakers work; they return stale cache or a degraded response rather than a hard error.

Relevant Axiom pages

What to do next

Back to Practice Lab