Tenacity Circuit Breaker Fallback
Guard a flaky dependency with a circuit breaker state machine, falling back to cached defaults and opening after repeated failures.
Code
import random
import time
from tenacity import RetryCallState, retry, stop_after_attempt, wait_fixed
class CircuitBreaker:
def __init__(self, failure_threshold: int = 3, cooldown: float = 5.0):
self.failure_threshold = failure_threshold
self.cooldown = cooldown
self.failures = 0
self.opened_at: float | None = None
def allow(self) -> bool:
if self.opened_at is None:
return True
if time.monotonic() - self.opened_at >= self.cooldown:
self.opened_at = None # 半开:放行试探请求
self.failures = 0
return True
return False
def record(self, success: bool) -> None:
if success:
self.failures = 0
self.opened_at = None
else:
self.failures += 1
if self.failures >= self.failure_threshold:
self.opened_at = time.monotonic()
breaker = CircuitBreaker(failure_threshold=3, cooldown=5)
FALLBACK_RATES = {'usd': 1.0, 'eur': 0.92}
def after_attempts(retry_state: RetryCallState) -> None:
breaker.record(retry_state.outcome.failed)
@retry(stop=stop_after_attempt(2), wait=wait_fixed(0.1),
after=after_attempts, reraise=True)
def call_rate_api() -> dict:
if random.random() < 0.6:
raise ConnectionError('rates service flaky')
return {'usd': 1.0, 'eur': 0.91}
def get_rates() -> tuple[dict, str]:
if not breaker.allow():
return FALLBACK_RATES, 'fallback-open'
try:
return call_rate_api(), 'live'
except ConnectionError:
return FALLBACK_RATES, 'fallback-error'
for _ in range(8):
rates, source = get_rates()
print('source:', source, 'usd:', rates['usd'])Report a problem with this exampleOpens a pre-filled issue on GitHub.