Fun with Learning Technology
LearnCoursesQuestionsTracksToolsNewsExplorePractice
Fun with Learning Technology

A new problem, explained clearly, every day.

Subscribe
Learn
  • Lessons
  • Topics
  • News
  • Tools
  • Courses
  • Career tracks
  • Everything
Site
  • About
  • Contact
  • Support
  • Privacy
  • Terms
Get the daily one

One email per new problem. No spam.

Request a tutorial

Requests shape what gets made next.

© 2026 Fun with Learning TechnologyRSS
Home›Courses›System Design›Circuit Breaker Pattern

Architecture Patterns

Circuit Breaker Pattern

The Circuit Breaker pattern is a stability design pattern used to prevent an application from repeatedly trying to execute an operation that is likely to fail. It acts as a protective mechanism that stops requests from reaching a failing downstream dependency, allowing the system to recover gracefully. You reach for this pattern when integrating with volatile remote services to prevent cascading failures across your distributed infrastructure.

The Core Concept of State Transitions

The Circuit Breaker operates as a finite state machine, essentially mirroring the functionality of an electrical circuit breaker in your home. It begins in the 'Closed' state, allowing traffic to flow normally to the downstream service. When the failure rate of the downstream service exceeds a predefined threshold, the breaker 'trips' and enters the 'Open' state. In this state, the breaker immediately rejects all incoming requests without attempting to invoke the remote service, thereby providing the dependency time to recover. This mechanism is crucial because it prevents a failing system from being overwhelmed by retries or blocked by waiting threads that consume precious memory and CPU resources. Understanding the transition logic allows architects to prevent resource exhaustion, which is the primary cause of total system collapse during partial outages.

class CircuitBreaker {
  constructor(threshold) {
    this.threshold = threshold;
    this.failures = 0;
    this.state = 'CLOSED'; // States: CLOSED, OPEN
  }
  async execute(fn) {
    if (this.state === 'OPEN') throw new Error('Circuit is open');
    try {
      const result = await fn();
      this.failures = 0; // Reset on success
      return result;
    } catch (e) {
      this.failures++;
      if (this.failures >= this.threshold) this.state = 'OPEN';
      throw e;
    }
  }
}

Implementing a Reset Mechanism

If a circuit remains in the 'Open' state indefinitely, the system will never recover because it stops sending requests even after the underlying service might have been restored. To solve this, we introduce the 'Half-Open' state. After a configured timeout period has elapsed, the circuit breaker transitions from 'Open' to 'Half-Open'. In this state, the breaker permits a limited number of test requests to pass through to the downstream service. If these requests succeed, the breaker assumes the dependency is healthy and transitions back to 'Closed', resetting the failure counter to zero. If they fail, it immediately returns to the 'Open' state. This approach ensures the system is self-healing, as it continuously probes the health of external dependencies without requiring manual intervention, effectively automating the recovery phase of the infrastructure's lifecycle.

const State = { CLOSED: 0, OPEN: 1, HALF_OPEN: 2 };
// Logic to manage auto-recovery after timeout
checkTimeout(breaker) {
  if (Date.now() - breaker.lastFailureTime > 5000) {
    breaker.state = State.HALF_OPEN;
  }
}

Handling Failures with Fallbacks

When the circuit is 'Open', the system still needs to provide some level of functionality to the user, rather than simply throwing an error. This is where the fallback strategy becomes essential. A fallback is a predefined path that executes when the main operation cannot proceed. This might involve returning a cached value, a default configuration, or a generic response that indicates the service is currently degraded. By designing for failure, you ensure that your application provides a consistent experience even when its components are failing. The effectiveness of a fallback depends on how gracefully it degrades the functionality—returning static content is always superior to a total application crash. Effectively managed fallbacks allow the frontend to display meaningful messages to users, maintaining trust despite internal technical difficulties.

async callService(request) {
  try {
    return await breaker.execute(() => remoteCall(request));
  } catch (e) {
    // Fallback: return cached result instead of failing
    return await getCache(request.key);
  }
}

Threshold Sensitivity and Tuning

The success of a circuit breaker depends entirely on how the failure threshold is defined. If the threshold is too low, the breaker will trip on transient, minor glitches, leading to an unnecessarily degraded user experience. Conversely, if the threshold is too high, the system will continue to bombard a struggling downstream dependency with requests, potentially worsening the outage or exhausting your own resources. Architects must analyze the typical behavior of the downstream service to determine appropriate settings. Monitoring metrics such as error rates, request latency, and the duration of dependencies allows for fine-tuning. By applying empirical data to your configuration, you ensure that the circuit breaker triggers only when there is a genuine, sustained issue, thus balancing responsiveness with protection in highly dynamic environments.

const config = {
  maxFailures: 5,
  timeout: 10000, // 10s wait before half-open
  requestWindow: 60000 // Error rate window in ms
};
const cb = new CircuitBreaker(config);

Distributed Circuit Breakers

In a truly distributed architecture, a single instance of a service might have multiple nodes, each maintaining its own circuit breaker status. This can lead to inconsistent behavior where some nodes stop traffic while others continue to send requests to a failing service. To address this, organizations often employ a centralized, shared state for the circuit breaker, typically stored in a high-performance, in-memory data store. This allows all service instances to act in concert based on a global view of the dependency health. However, there is a trade-off: using a centralized store introduces its own latency and potential points of failure. Engineers must weigh the benefits of a global state against the simplicity and speed of local node-level circuit breakers when designing their infrastructure recovery strategy.

async function distributedExecute(fn) {
  const isGlobalOpen = await redis.get('circuit_status');
  if (isGlobalOpen === 'OPEN') return getFallback();
  
  try {
    return await fn();
  } catch (e) {
    await redis.incr('failure_count');
    throw e;
  }
}

Key points

  • Circuit breakers act as a firewall to prevent cascading failure in distributed systems.
  • The CLOSED state permits traffic, while the OPEN state blocks all requests.
  • The HALF-OPEN state provides a mechanism for testing if a service has recovered.
  • Failures should trigger a graceful fallback to ensure the user experience is maintained.
  • Thresholds must be tuned based on observed metrics rather than arbitrary guesses.
  • Circuit breakers reduce the load on struggling services by stopping incoming request volume.
  • Distributed systems require careful consideration of whether to share breaker states globally.
  • Automatic recovery logic is essential for minimizing human intervention during system outages.

Common mistakes

  • Mistake: Implementing a global circuit breaker for all services. Why it's wrong: This creates a single point of failure and makes the entire system vulnerable to cascading failures. Fix: Use granular, service-specific breakers to isolate faults.
  • Mistake: Failing to define a meaningful fallback strategy. Why it's wrong: When the circuit opens, the system stops returning data, breaking the user experience. Fix: Always implement a fallback, such as returning cached data, a default response, or a polite error message.
  • Mistake: Setting the 'failure threshold' too low. Why it's wrong: Transient network glitches might trigger the breaker, causing unnecessary service outages. Fix: Analyze latency and error patterns to set a threshold that tolerates minor blips while catching genuine failures.
  • Mistake: Overlooking the 'half-open' state logic. Why it's wrong: Without this, a service might remain permanently disabled even after the underlying fault is resolved. Fix: Configure a probe mechanism to test the service intermittently when the breaker is half-open to decide whether to close the circuit.
  • Mistake: Configuring the circuit breaker without considering timeout integration. Why it's wrong: If the timeout is longer than the circuit breaker's reaction time, the system will still hang while waiting for the remote service. Fix: Ensure timeouts are significantly shorter than the circuit breaker thresholds to fail fast.

Interview questions

What is the primary purpose of the Circuit Breaker pattern in distributed systems?

The primary purpose of the Circuit Breaker pattern is to prevent a system from repeatedly trying to execute an operation that is likely to fail. In a microservices architecture, if a downstream service is struggling or unresponsive, continuing to send requests adds load and consumes limited resources like thread pools and memory. By 'tripping' the circuit, we fail fast, protecting the system from cascading failures and allowing the struggling downstream service the breathing room it needs to recover.

Can you explain the three states of a Circuit Breaker?

The Circuit Breaker exists in three distinct states: Closed, Open, and Half-Open. In the 'Closed' state, requests flow normally to the downstream service. When the failure rate exceeds a defined threshold, the circuit transitions to 'Open', where all requests fail immediately without attempting the call. After a predetermined timeout, it enters 'Half-Open', where it allows a limited number of test requests. If these succeed, it transitions back to Closed; otherwise, it returns to Open.

Compare the 'Fail Fast' approach of a Circuit Breaker with the 'Retry Pattern'. When should you use one over the other?

The Retry Pattern and Circuit Breaker are complementary but solve different problems. Retry is effective for transient, short-lived glitches, such as a temporary network blip or a momentary load spike. However, if a service is truly down, retrying only worsens the situation by amplifying the load. Use Retry for intermittent issues, but use a Circuit Breaker when the underlying service is likely experiencing a sustained failure, to prevent resource exhaustion and allow for system recovery.

How do you determine the appropriate failure threshold for a Circuit Breaker in a production environment?

Determining the threshold requires analyzing the service's SLOs and traffic patterns. If you set it too low, you might trigger the circuit prematurely due to minor, acceptable spikes in latency or noise, resulting in unnecessary downtime. If set too high, you risk saturating your own infrastructure before the circuit trips. Usually, teams use a combination of error rates (e.g., 50% failures over 10 seconds) and absolute counts, constantly tuning these values based on observed metrics and tail latency distributions during stress testing.

How should an application handle a request when the Circuit Breaker is in the 'Open' state?

When the circuit is open, we must provide a graceful degradation strategy rather than just throwing an error to the user. This is often handled via a fallback method. You could return a cached version of the data, provide a default 'safe' response, or redirect the user to a secondary, less critical service. By implementing a fallback, we maintain a positive user experience, ensuring that the entire interface does not break even if a specific auxiliary service is currently unavailable.

How would you implement a distributed Circuit Breaker pattern where state is shared across multiple instances of a service?

Implementing a distributed Circuit Breaker involves moving the state management from local memory to a centralized store like a distributed cache. By using a shared store, all instances of your service can collectively monitor the failure rate of a downstream dependency. For example, if instance A sees a failure, it updates the count in the shared cache. Once the global threshold is hit, all instances trip their circuits simultaneously, providing a unified defense against a failing downstream system.

All System Design interview questions →

Check yourself

1. What is the primary design goal of the Circuit Breaker pattern in a distributed architecture?

  • A.To increase the processing capacity of the downstream service
  • B.To prevent a fault in one service from cascading to others
  • C.To enforce strict data consistency across all microservices
  • D.To automatically scale up server resources during traffic spikes
Show answer

B. To prevent a fault in one service from cascading to others
The pattern prevents cascading failure by stopping requests to an unhealthy service. Option 0 is wrong as it doesn't increase capacity. Option 2 is a database concern, not a breaker function. Option 3 describes load balancing or auto-scaling.

2. When a circuit is in the 'Open' state, how should the system behave when a new request arrives?

  • A.It should wait for a timeout before returning an error
  • B.It should attempt to call the downstream service anyway
  • C.It should immediately execute a fallback mechanism or return an error
  • D.It should queue the request until the service recovers
Show answer

C. It should immediately execute a fallback mechanism or return an error
An 'Open' circuit represents a confirmed failure, so it must 'fail fast' via a fallback. Option 0 causes latency, option 1 defeats the purpose of the breaker, and option 3 creates memory pressure in the queue.

3. Why is it important to include a 'Half-Open' state in the circuit breaker state machine?

  • A.To allow the system to slowly throttle traffic back to normal levels
  • B.To perform a health check on the downstream service without overwhelming it
  • C.To force the service to restart if it is still unresponsive
  • D.To bypass the circuit breaker entirely for administrative traffic
Show answer

B. To perform a health check on the downstream service without overwhelming it
The 'Half-Open' state tests if the dependency is healthy before fully reopening. Option 0 describes rate limiting. Option 2 is a deployment/orchestration task. Option 3 undermines the pattern's safety.

4. A service has a circuit breaker with a high failure threshold. What is the most likely consequence during a partial outage?

  • A.The system will suffer from high latency as it repeatedly attempts to contact the failing service
  • B.The system will recover instantly once the service is fixed
  • C.The system will be overly sensitive and trip the breaker for minor issues
  • D.The system will correctly identify the issue and immediately initiate a rollback
Show answer

A. The system will suffer from high latency as it repeatedly attempts to contact the failing service
A high threshold allows too many failing requests to pass before tripping, keeping the system waiting. Options 1 and 3 are incorrect because a high threshold delays reaction, and option 2 is irrelevant to the threshold setting.

5. Which scenario best justifies implementing a Circuit Breaker pattern?

  • A.A service that performs heavy read/write operations to a local database
  • B.Two services that communicate synchronously over a network
  • C.A batch processing system running on a single server
  • D.A frontend application that requires low-latency rendering
Show answer

B. Two services that communicate synchronously over a network
Synchronous remote calls are the primary sources of cascading failures. Option 0 is a local operation. Option 2 is isolated. Option 3 is a UI concern rather than a service-to-service communication issue.

Take the full System Design quiz →

← PreviousAPI Gateway PatternNext →CQRS and Event Sourcing

System Design

31 lessons, free to read.

All lessons →

Track your progress

Sign in to mark lessons done, score quizzes and keep notes.

Open in the app