Problem Statement
When a microservice calls another service that is slow or down, the calling service waits too long or fails repeatedly, causing cascading failures and degraded user experience across the system.
Jump into concepts and practice - no test required
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ Client │──────▶│ Circuit Breaker│──────▶│ Downstream │
│ (Caller) │ │ (Monitor & │ │ Service │
│ │ │ Control) │ │ │
└───────────────┘ └───────────────┘ └───────────────┘
▲ │ ▲ │
│ │ │ │
│ │ └───── Failure count ─┘
│ │
└───────── Success / Failure feedback ──────────┘This diagram shows the client calling a downstream service through a circuit breaker that monitors success and failure to decide whether to allow or block requests.
### Before: No circuit breaker, direct call class ServiceClient: def call_service(self): response = external_service_request() return response ### After: Circuit breaker applied import time class CircuitBreaker: def __init__(self, failure_threshold=3, recovery_time=10): self.failure_threshold = failure_threshold self.recovery_time = recovery_time self.failure_count = 0 self.last_failure_time = None self.state = 'CLOSED' # CLOSED, OPEN, HALF_OPEN def call(self, func, *args, **kwargs): if self.state == 'OPEN': if time.time() - self.last_failure_time > self.recovery_time: self.state = 'HALF_OPEN' else: raise Exception('Circuit breaker is OPEN') try: result = func(*args, **kwargs) except Exception: self.failure_count += 1 self.last_failure_time = time.time() if self.failure_count >= self.failure_threshold: self.state = 'OPEN' raise else: self.failure_count = 0 if self.state == 'HALF_OPEN': self.state = 'CLOSED' return result class ServiceClientWithCB: def __init__(self): self.circuit_breaker = CircuitBreaker() def call_service(self): return self.circuit_breaker.call(external_service_request) # external_service_request is a placeholder for the actual call
circuit breaker pattern in microservices?if state == 'OPEN':
return 'fail fast'
elif state == 'HALF_OPEN':
if test_call_successful():
state = 'CLOSED'
else:
state = 'OPEN'
else:
call_service()
What happens when the circuit breaker is in HALF_OPEN state and the test call fails?