Circuit Breaker

Level: Advanced 60–90 min

Concepts: Design PatternsStateMockingBoundariesEdge Cases


Implement the circuit breaker pattern to protect against cascading failures when calling unreliable external services.

Requirements

A circuit breaker has three states: Closed, Open, and Half-Open.

  1. Closed (normal operation)

    • Requests pass through to the underlying service
    • Track consecutive failures
    • When failures reach the failure threshold, transition to Open
    • Successes reset the failure counter
  2. Open (failing fast)

    • All requests fail immediately without calling the service
    • After the reset timeout expires, transition to Half-Open
  3. Half-Open (testing recovery)

    • Allow a single request through to the service
    • If it succeeds, transition to Closed and reset counters
    • If it fails, transition back to Open and restart the timeout

Configuration:

  • failureThreshold — number of consecutive failures before opening (default: 3)
  • resetTimeout — seconds to wait before transitioning from Open to Half-Open (default: 30)

The circuit breaker should accept an injectable clock for testability.

Test Cases

Given a circuit breaker with threshold=3 and timeout=30s:

StepStateActionService ResultCircuit Breaker ResultNew State
1ClosedcallsuccesssuccessClosed
2ClosedcallfailurefailureClosed (1 fail)
3ClosedcallfailurefailureClosed (2 fails)
4ClosedcallfailurefailureOpen (3 fails = threshold)
5Opencallfail immediatelyOpen
6Open +30scallsuccesssuccessClosed
7Open +30scallfailurefailureOpen (restart timeout)

Additional cases:

  • Success in Closed state resets failure count to 0
  • Multiple successes after failures keep the counter at 0
  • Open state does not call the underlying service at all
  • Half-Open allows exactly one request through

Bonus

  • Add an onStateChange callback that fires when the state transitions
  • Add getState() to inspect the current state
  • Add getMetrics() returning success count, failure count, and rejection count
  • Implement a half-open quota — allow N requests through in half-open instead of just 1
  • Add exponential backoff — double the reset timeout after each Open→Half-Open→Open cycle