DEV Community

Cover image for The Circuit Breaker Pattern in Microservices: Protecting Downstream Dependencies
DEVANSHU PATIL
DEVANSHU PATIL

Posted on AI-assisted

The Circuit Breaker Pattern in Microservices: Protecting Downstream Dependencies

The Circuit Breaker Pattern in Microservices: Protecting Downstream Dependencies

In a microservices ecosystem, service failure is contagious.

Suppose Service A calls Service B, which depends on an external shipping carrier API. If the shipping API begins timing out with 30-second delays, requests in Service B pile up. Threads stay blocked waiting for sockets, database connection pools exhaust, and Service B's memory spikes until it crashes.

Now, Service A's connection pools exhaust waiting for Service B, and the outage cascades all the way to your customer checkout page!

To halt cascading collapses, resilient systems implement the Circuit Breaker Pattern.

The Circuit Breaker State Machine

        +-------------------------------------------------+
        |                                                 |
        v                                                 |
  +------------+   Failure Threshold Exceeded  +----------+---+
  |   CLOSED   | ----------------------------> |     OPEN     |
  +------------+                               +--------------+
        ^                                             |
        | Success Threshold Met                       | Sleep Window Expires
        |                                             v
  +------------+                               +--------------+
  |  HALF-OPEN | <---------------------------- |  (Testing)   |
  +------------+                               +--------------+
        |                                             ^
        +---------- Failure Encountered --------------+
Enter fullscreen mode Exit fullscreen mode
  1. CLOSED (Normal Operation): Requests pass through to the downstream service.
  2. OPEN (Fast Failure): All requests to the dependency are immediately rejected locally without making a network call!
  3. HALF-OPEN (Trial Probe): Permits a small percentage of probe requests. If successful, resets to CLOSED.

Python Circuit Breaker Implementation

import time
import threading
from typing import Callable, Any

class CircuitBreakerOpenException(Exception):
    pass

class CircuitBreaker:
    def __init__(self, failure_threshold: int = 5, recovery_time_seconds: float = 30.0):
        self.failure_threshold = failure_threshold
        self.recovery_time = recovery_time_seconds
        self.state = "CLOSED"
        self.failure_count = 0
        self.last_failure_time = 0.0
        self.lock = threading.Lock()

    def call(self, func: Callable, *args, **kwargs) -> Any:
        with self.lock:
            now = time.time()
            if self.state == "OPEN":
                if now - self.last_failure_time > self.recovery_time:
                    self.state = "HALF-OPEN"
                else:
                    raise CircuitBreakerOpenException("Circuit is OPEN. Service unavailable.")

        try:
            result = func(*args, **kwargs)
            with self.lock:
                if self.state == "HALF-OPEN":
                    self.state = "CLOSED"
                    self.failure_count = 0
            return result

        except Exception as e:
            with self.lock:
                self.failure_count += 1
                self.last_failure_time = time.time()
                if self.state in ("CLOSED", "HALF-OPEN") and self.failure_count >= self.failure_threshold:
                    self.state = "OPEN"
            raise e
Enter fullscreen mode Exit fullscreen mode

Real-World Usage with Fallbacks

import requests

cb = CircuitBreaker(failure_threshold=3, recovery_time_seconds=10.0)

def fetch_shipping_rates(weight: float):
    resp = requests.get(f"https://api.carrier.com/rates?weight={weight}", timeout=2.0)
    resp.raise_for_status()
    return resp.json()

def get_rates_with_fallback(weight: float):
    try:
        return cb.call(fetch_shipping_rates, weight)
    except (CircuitBreakerOpenException, requests.RequestException):
        return {"rate": 15.00, "source": "fallback_estimate"}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)