payment_breaker=CircuitBreaker(failure_threshold=3,recovery_timeout=60)defprocess_payment(order):ifnotpayment_breaker.can_execute():raiseServiceUnavailable("Payment service circuit open")try:result=payment_service.charge(order)payment_breaker.record_success()returnresultexceptExceptionase:payment_breaker.record_failure()raise
fromfunctoolsimportwrapsdefcircuit_breaker(breaker:CircuitBreaker):defdecorator(func):@wraps(func)defwrapper(*args,**kwargs):ifnotbreaker.can_execute():raiseCircuitOpenError(f"Circuit breaker open for {func.__name__}")try:result=func(*args,**kwargs)breaker.record_success()returnresultexceptExceptionase:breaker.record_failure()raisereturnwrapperreturndecorator# Usagepayment_cb=CircuitBreaker()@circuit_breaker(payment_cb)defcharge_customer(customer_id,amount):returnpayment_api.charge(customer_id,amount)
defget_user_recommendations(user_id):ifnotrecommendations_breaker.can_execute():# Fallback to cached or default recommendationsreturnget_cached_recommendations(user_id)orDEFAULT_RECOMMENDATIONStry:result=recommendations_service.get(user_id)recommendations_breaker.record_success()returnresultexceptException:recommendations_breaker.record_failure()returnget_cached_recommendations(user_id)orDEFAULT_RECOMMENDATIONS
classServiceRegistry:def__init__(self):self.breakers={}defget_breaker(self,service_name:str)->CircuitBreaker:ifservice_namenotinself.breakers:self.breakers[service_name]=CircuitBreaker()returnself.breakers[service_name]registry=ServiceRegistry()defcall_service(service_name:str,endpoint:str):breaker=registry.get_breaker(service_name)ifnotbreaker.can_execute():raiseServiceUnavailable(f"{service_name} circuit is open")try:result=http_client.get(f"http://{service_name}/{endpoint}")breaker.record_success()returnresultexceptException:breaker.record_failure()raise
fromprometheus_clientimportCounter,Gaugecircuit_state=Gauge('circuit_breaker_state','Circuit breaker state (0=closed, 1=open, 2=half-open)',['service'])circuit_failures=Counter('circuit_breaker_failures_total','Circuit breaker failure count',['service'])circuit_rejections=Counter('circuit_breaker_rejections_total','Requests rejected by open circuit',['service'])# Update metrics in circuit breakerdefrecord_failure(self,service_name):circuit_failures.labels(service=service_name).inc()# ... rest of failure logiccircuit_state.labels(service=service_name).set(self.state.value)
# Bad: one failure affects all servicesglobal_breaker=CircuitBreaker()# Good: per-service breakerspayment_breaker=CircuitBreaker()inventory_breaker=CircuitBreaker()
2. No fallback
1
2
3
4
5
6
7
# Bad: just failsifnotbreaker.can_execute():raiseError()# Good: graceful degradationifnotbreaker.can_execute():returncached_response()ordefault_response()
3. Wrong failure detection
1
2
3
4
5
6
7
8
9
# Bad: all exceptions trip the breakerexceptException:breaker.record_failure()# Good: only infrastructure failuresexcept(ConnectionError,Timeout):breaker.record_failure()exceptValidationError:pass# Client error, not service failure