Circuit Breaker
Source: Custom
Topics: State machine, sync.Mutex, time, error handling
Problem
Implement a circuit breaker that wraps a fallible operation and stops calling it when it fails repeatedly.
States:
- Closed (normal) — calls pass through; failure counter increments on each error.
- Open (tripped) — calls return
ErrOpen immediately without executing; entered after maxFailures consecutive errors.
- Half-Open (probing) — after
cooldown elapses, exactly one call is allowed through as a probe; success → Closed, failure → Open again.
Requirements:
New(maxFailures int, cooldown time.Duration) *Breaker
Do(fn func() error) error — execute fn according to the current state.
ErrOpen sentinel error returned when the circuit is open.
- Successful calls reset the failure counter.
- Single-probe half-open: while a probe is in flight, all other concurrent callers must get
ErrOpen — you must not let a thundering herd hit a still-fragile backend.
Type:
var ErrOpen = errors.New("circuit open")
type Breaker struct { ... }
func New(maxFailures int, cooldown time.Duration) *Breaker
func (b *Breaker) Do(fn func() error) error
Key concepts
- Single mutex: protects state, failure counter, the
openUntil timestamp, and the
probing flag.
- Time-based transition: compare
time.Now() against openUntil inside Do to detect when cooldown has elapsed.
- Admit-then-run: decide under the lock whether a call may proceed (and whether it's the
probe), then run
fn outside the lock so a slow call doesn't block the whole breaker. A
probing flag set under the lock guarantees only one probe runs at a time.
- Reset on success: a successful probe closes the circuit and resets
failures to 0.
Run
go test -v -bench=. ./challenges/networking/circuit-breaker/
Sign in to submit your solution.