Skip to content

Circuit Breaker Pattern Explained — Complete Beginner's Guide

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about Circuit Breaker Pattern Explained. We cover key concepts, practical examples, and best practices to help you master this topic.

The circuit breaker pattern prevents cascading failures in Distributed Systems by monitoring for failures and stopping requests to a failing service before the failure spreads.

What You'll Learn

By the end of this tutorial, you will understand what the circuit breaker pattern is, its three states, why it matters, and how it differs from retry strategies.

Why It Matters

Without circuit breakers, a single failing service can cascade failures across your entire system. DodaTech uses circuit breakers in every microservice to contain failures.

Real-World Use

DodaZIP's conversion API uses circuit breakers around its file processing service. When the processor fails 5 times in a row, the circuit opens and subsequent requests fail immediately, preventing timeouts from accumulating.

Circuit Breaker Learning Path

flowchart LR
  A[Retry Strategies] --> B[Circuit Breaker]
  B --> C[Three States]
  B --> D[Implementation]
  B --> E{You Are Here}
  style E fill:#f90,color:#fff

What Is a Circuit Breaker?

A circuit breaker is like an electrical circuit breaker in your home. When too much current flows (too many failures), the breaker trips and stops the flow. Someone must reset it (half-open state) to test if the fault is cleared.

class SimpleCircuitBreaker {
  constructor() {
    this.state = "closed";
    this.failureCount = 0;
    this.threshold = 5;
    this.resetTimeout = 30000;
    this.nextAttempt = Date.now();
  }

  async call(fn) {
    if (this.state === "open") {
      if (Date.now() > this.nextAttempt) {
        this.state = "half-open";
      } else {
        throw new Error("Circuit breaker is open");
      }
    }

    try {
      const result = await fn();
      this.state = "closed";
      this.failureCount = 0;
      return result;
    } catch (err) {
      this.failureCount++;
      if (this.failureCount >= this.threshold) {
        this.state = "open";
        this.nextAttempt = Date.now() + this.resetTimeout;
      }
      throw err;
    }
  }
}

Circuit Breaker vs Retry

Retry and circuit breaker solve different problems and work best together.

Aspect Retry Circuit Breaker
Purpose Handle transient failures Prevent cascading failures
Behavior Try again Stop trying
Duration Seconds Minutes
Scope Single call All calls to a service

Why Circuit Breakers Matter

Without circuit breakers, a slow or failing downstream service causes all upstream services to accumulate waiting requests. This exhausts thread pools and memory, eventually taking down the entire system.

// Without circuit breaker: each request waits 30s for timeout
// 100 concurrent requests = 100 threads blocked for 30s
// Thread pool exhausts -> server stops accepting requests
// Cascading failure: every service that depends on this one also fails

Common Mistakes

  1. Setting threshold too high -- A threshold of 100 failures means 99 failures happen before protection kicks in. Start with 3-5.

  2. Opening circuit on every error -- Only open the circuit for errors that indicate real trouble (timeouts, connection failures), not client errors.

  3. Not logging state transitions -- Circuit breaker state changes are critical events. Log every open, close, and half-open transition.

  4. Using a single circuit for all services -- Different downstream services need different circuit breakers with different thresholds.

  5. Not implementing half-open probes -- Without half-open, a circuit stays open forever or flips open/closed rapidly.

Practice Questions

  1. What are the three states of a circuit breaker? Closed (normal operation), Open (rejecting requests), Half-open (testing recovery).

  2. How does a circuit breaker prevent cascading failures? By failing fast when a downstream service is unhealthy, preventing upstream resources from being consumed by waiting requests.

  3. What is the difference between circuit breaker and retry? Retry recovers from transient failures. Circuit breaker stops requests to prevent cascading failures from persistent problems.

  4. Challenge: Implement a circuit breaker that tracks failure rate over a time window.

class RateBasedCircuit {
  constructor(threshold = 0.5, windowMs = 60000) {
    this.threshold = threshold;
    this.windowMs = windowMs;
    this.results = [];
  }

  record(success) {
    this.results.push({ success, time: Date.now() });
    this.cleanup();
  }

  get failureRate() {
    const recent = this.results.filter(r => Date.now() - r.time < this.windowMs);
    if (recent.length < 10) return 0;
    return recent.filter(r => !r.success).length / recent.length;
  }
}

FAQ

What happens when the circuit is open?

Requests to the failing service fail immediately with an error instead of waiting for a timeout. This preserves resources.

How long should the circuit stay open?

30-60 seconds is standard. Long enough for transient issues to resolve, short enough to minimize downtime.

Can the circuit breaker close immediately after opening?

No. It must transition through half-open first to verify the service has recovered.

Should I use circuit breakers for database connections?

Yes. Database connection failures are a common use case for circuit breakers.

How do I test circuit breaker behavior?

Mock a service that fails N times, then succeeds. Verify the circuit opens after N failures and closes after recovery.

Mini Project

Build a basic circuit breaker with configurable threshold, reset timeout, state change events, and logging.

class CircuitBreaker {
  constructor(options = {}) {
    this.threshold = options.threshold || 5;
    this.resetTimeout = options.resetTimeout || 30000;
    this.state = "closed";
    this.failureCount = 0;
    this.nextAttempt = Date.now();
    this.onStateChange = options.onStateChange || (() => {});
  }

  async exec(fn) {
    if (this.state === "open") {
      if (Date.now() >= this.nextAttempt) {
        this.transitionTo("half-open");
      } else {
        throw new Error("Circuit open, request rejected");
      }
    }

    try {
      const result = await fn();
      if (this.state === "half-open") {
        this.transitionTo("closed");
      }
      this.failureCount = 0;
      return result;
    } catch (err) {
      this.failureCount++;
      if (this.failureCount >= this.threshold || this.state === "half-open") {
        this.transitionTo("open");
        this.nextAttempt = Date.now() + this.resetTimeout;
      }
      throw err;
    }
  }

  transitionTo(newState) {
    const oldState = this.state;
    this.state = newState;
    this.onStateChange({ from: oldState, to: newState, time: new Date().toISOString() });
    console.log(`Circuit breaker: ${oldState} -> ${newState}`);
  }

  getState() {
    return {
      state: this.state,
      failureCount: this.failureCount,
      nextAttempt: new Date(this.nextAttempt).toISOString()
    };
  }
}

const cb = new CircuitBreaker({
  threshold: 3,
  resetTimeout: 10000,
  onStateChange: (event) => console.log("State change:", event)
});

async function test() {
  const failingFn = () => Promise.reject(new Error("fail"));
  const successFn = () => Promise.resolve("ok");

  for (let i = 0; i < 5; i++) {
    try { await cb.exec(failingFn); }
    catch (e) { console.log(`Call ${i + 1}:`, e.message); }
  }

  console.log("State:", cb.getState());
}

What's Next

Now that you understand circuit breaker basics, explore the three states in detail. Then learn about implementing circuit breakers in Node.js.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro