Circuit Breaker
A circuit breaker is a fault tolerance pattern borrowed from electrical engineering. When a downstream service fails repeatedly, the circuit breaker “opens” and blocks requests for a cooldown period. This prevents your application from wasting resources on doomed calls and shields the struggling service from further overload.
How It Works
A circuit breaker has three states:
- Closed (normal): Requests pass through. Failures are counted.
- Open (tripped): Requests are immediately rejected without calling the service. A timer starts.
- Half-open (testing): After the cooldown, one request is allowed through. If it succeeds, the circuit closes. If it fails, the circuit reopens.
Closed ──(failure threshold reached)──→ Open ↑ │ │ (cooldown expires) │ ↓ └───────(test request succeeds)─── Half-OpenExample
class CircuitBreaker { constructor({ threshold = 5, cooldown = 30000 }) { this.failures = 0; this.threshold = threshold; this.cooldown = cooldown; this.state = 'closed'; this.nextAttempt = 0; }
async call(fn) { if (this.state === 'open') { if (Date.now() < this.nextAttempt) { throw new Error('Circuit breaker is open'); } this.state = 'half-open'; }
try { const result = await fn(); this.failures = 0; this.state = 'closed'; return result; } catch (error) { this.failures++; if (this.failures >= this.threshold) { this.state = 'open'; this.nextAttempt = Date.now() + this.cooldown; } throw error; } }}
const breaker = new CircuitBreaker({ threshold: 3, cooldown: 10000 });const data = await breaker.call(() => fetch('https://api.example.com/data'));When to Use Circuit Breakers
- Calling external APIs that may become unavailable
- Connecting to databases or caches that can go down
- Any dependency where repeated failures would cascade to callers
Circuit Breakers vs. Retries
Retries re-attempt a single failed request. Circuit breakers block all requests to a service after a pattern of failure. They work best together: retry individual failures, and open the circuit when retries fail consistently.