Circuit Breaker
Level: Advanced 60–90 minConcepts: 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.
-
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
-
Open (failing fast)
- All requests fail immediately without calling the service
- After the reset timeout expires, transition to Half-Open
-
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:
| Step | State | Action | Service Result | Circuit Breaker Result | New State |
|---|---|---|---|---|---|
| 1 | Closed | call | success | success | Closed |
| 2 | Closed | call | failure | failure | Closed (1 fail) |
| 3 | Closed | call | failure | failure | Closed (2 fails) |
| 4 | Closed | call | failure | failure | Open (3 fails = threshold) |
| 5 | Open | call | — | fail immediately | Open |
| 6 | Open +30s | call | success | success | Closed |
| 7 | Open +30s | call | failure | failure | Open (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
onStateChangecallback 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