SOFTWARE ARCHITECTURE / SYSTEM CONCEPT BRIEF

Circuit breaker

A circuit breaker wraps calls to a dependency and stops calling it when it is failing, so the caller fails fast instead of waiting on timeouts and piling up threads.

IntermediatePhase 08 / Topic 12 of 17RequirementsTrade-offsFailure modes
01

Overview

A circuit breaker wraps calls to a dependency and stops calling it when it is failing, so the caller fails fast instead of waiting on timeouts and piling up threads. Like an electrical breaker, it has three states: closed (calls flow normally while failures are counted), open (calls are rejected immediately for a cool-down period), and half-open (a few trial calls test whether the dependency has recovered).

Circuit breakers protect both sides: the caller keeps its resources free, and the struggling dependency gets breathing room to recover instead of being hammered by retries. They are usually combined with timeouts, fallbacks, and metrics.

An electrical circuit breaker

When too much current flows, the breaker trips and cuts power to protect the wiring. After a while, you try flipping it back on; if the fault is fixed, power flows again, otherwise it trips again.

02

When to use it

  • Calls to remote services that can fail or become slow.
  • Preventing cascading failures in microservices.
  • Third-party APIs with outages.
  • Anywhere retries could overwhelm a struggling dependency.
03

Where it shows up in interviews

Failing dependency protection

Recognize it when: a downstream outage causes timeouts everywhere.

  • Design a resilient product page
  • Design a payment gateway integration
04

Where it is used in real software

Netflix Hystrix

Popularized circuit breakers for microservices; now in maintenance, replaced by Resilience4j.

Resilience4j and Polly

Standard libraries for Java and .NET.

Envoy outlier detection

Ejects failing hosts from load balancing pools automatically.

05

Key terms

Closed
Normal operation; failures are counted.
Open
Calls fail immediately without reaching the dependency.
Half-open
Limited trial calls to test recovery.
Failure threshold
Error or slow-call rate that trips the breaker.
Sliding window
Recent calls used to compute the failure rate.
06

How it works, step by step

  1. 1
    Closed: count outcomes

    Track failures and slow calls in a sliding window.

  2. 2
    Trip to open

    When the failure rate exceeds the threshold (with a minimum number of calls).

  3. 3
    Open: fail fast

    Return a fallback or error immediately.

  4. 4
    After the wait time: half-open

    Allow a few trial calls.

  5. 5
    Close or re-open

    Trials succeed: close; fail: open again.

Circuit breaker states
Step 1 / 4
Closed
Open
Half-open

STEP 1Closed: calls pass through. 3 of the last 20 calls failed (15%), below the 50% threshold.

07

Timeline of an outage with a breaker

Threshold 50% over 20 calls, open for 30 s

Step 1 / 5
TimeDependencyBreakerCaller experience
0 sHealthyClosedNormal responses
10 sFailingClosed, countingSome requests wait for timeouts
12 sFailingOpenInstant fallback, threads freed
42 sRecoveredHalf-openTrial calls succeed
43 sHealthyClosedNormal responses

NOWTime: 0 s | Dependency: Healthy | Breaker: Closed | Caller experience: Normal responses

Without the breaker, every request during the outage would wait for a timeout, exhausting threads and spreading the failure.

08

Implementation

type State = "closed" | "open" | "half-open"; export class CircuitBreaker {  private state: State = "closed";  private results: boolean[] = [];  private openedAt = 0;  private trials = 0;   constructor(private opts = { window: 20, minCalls: 10, failureRate: 0.5, openMs: 30_000, halfOpenTrials: 3 }) {}   async call<T>(fn: () => Promise<T>, fallback: () => T): Promise<T> {    if (this.state === "open") {      if (Date.now() - this.openedAt < this.opts.openMs) return fallback();      this.state = "half-open";      this.trials = 0;    }    if (this.state === "half-open" && this.trials >= this.opts.halfOpenTrials) return fallback();    if (this.state === "half-open") this.trials++;     try {      const value = await fn();      this.record(true);      return value;    } catch {      this.record(false);      return fallback();    }  }   private record(ok: boolean) {    if (this.state === "half-open") {      if (!ok) return this.trip();      if (this.trials >= this.opts.halfOpenTrials) { this.state = "closed"; this.results = []; }      return;    }    this.results = [...this.results.slice(-(this.opts.window - 1)), ok];    const failures = this.results.filter((r) => !r).length;    if (this.results.length >= this.opts.minCalls && failures / this.results.length >= this.opts.failureRate) this.trip();  }   private trip() { this.state = "open"; this.openedAt = Date.now(); }}
09

Complexity and performance

Overhead per callO(1)

Counter updates.

Detection time~window of calls

Needs minimum volume.

10

Trade-offs

Sensitivity

Low thresholds trip on brief blips and cause unnecessary fallbacks; high thresholds react too slowly.

Per-host vs per-service breakers

Per-service breakers can open because of one bad host; per-host (outlier detection) is more precise.

11

Variants and related techniques

Slow-call breakers

Trip on latency, not only errors.

Adaptive concurrency limits

Reduce allowed in-flight requests as latency rises (Netflix concurrency-limits).

12

Common mistakes

  • Counting client errors (400s) as failures.

    Fix: Only count dependency failures (timeouts, 5xx).

  • No fallback strategy.

    Fix: Decide what to return when open: cached data, default, or clear error.

  • Breakers without monitoring.

    Fix: Emit state changes as metrics and alerts.

13

Interview questions

Explain the circuit breaker pattern.

A wrapper that counts failures of calls to a dependency. When failures exceed a threshold it opens and rejects calls immediately for a cool-down, then half-opens to test with a few calls, closing if they succeed. It prevents wasting resources on a failing dependency and lets it recover.

How do retries and circuit breakers interact?

Retries handle brief transient errors; the circuit breaker stops retries from hammering a dependency that is persistently failing. The breaker usually wraps the retry logic so an open breaker short-circuits all attempts.

14

Practice problems

ProblemDifficultyWhat it trains
Implement a circuit breaker with half-open stateMediumState machine.
Choose thresholds for a payment provider breakerMediumSensitivity.