from __future__ import annotations import time from enum import Enum class CircuitBreakerState(Enum): CLOSED = "closed" OPEN = "open" HALF_OPEN = "half_open" class CircuitBreaker: """标准断路器,冷却后自动半开。""" def __init__( self, name: str, failure_threshold: int = 5, cooldown_seconds: float = 30.0, ) -> None: self.name = name self.failure_threshold = failure_threshold self.cooldown_seconds = cooldown_seconds self._state = CircuitBreakerState.CLOSED self._failure_count = 0 self._last_failure_time: float = 0.0 @property def state(self) -> CircuitBreakerState: if ( self._state == CircuitBreakerState.OPEN and time.monotonic() - self._last_failure_time >= self.cooldown_seconds ): self._state = CircuitBreakerState.HALF_OPEN return self._state def record_success(self) -> None: self._failure_count = 0 self._state = CircuitBreakerState.CLOSED def record_failure(self) -> None: self._failure_count += 1 self._last_failure_time = time.monotonic() if self._failure_count >= self.failure_threshold: self._state = CircuitBreakerState.OPEN def allow_request(self) -> bool: return self.state != CircuitBreakerState.OPEN class RetryStrategy: """指数退避重试。""" def __init__( self, max_retries: int = 3, base_delay: float = 1.0, max_delay: float = 60.0, multiplier: float = 2.0, ) -> None: self.max_retries = max_retries self.base_delay = base_delay self.max_delay = max_delay self.multiplier = multiplier def should_retry(self, attempt_index: int) -> bool: return attempt_index < self.max_retries def get_delay(self, attempt_index: int) -> float: delay = self.base_delay * (self.multiplier**attempt_index) return min(delay, self.max_delay) class DowngradeAction: """降级链中的一个步骤。""" def __init__(self, type: str, target: str) -> None: # noqa: A002 self.type = type # "fallback_endpoint", "fallback_model", "cache", "degrade_quality" self.target = target class DowngradeChain: """当模型/端点失败时的降级动作链。""" def __init__(self, actions: list[DowngradeAction]) -> None: self._actions = actions self._index = 0 def next_action(self) -> tuple[str, str] | None: if self._index >= len(self._actions): return None action = self._actions[self._index] return (action.type, action.target) def advance(self) -> None: self._index += 1 def is_exhausted(self) -> bool: return self._index >= len(self._actions) def reset(self) -> None: self._index = 0 class ResilienceFactory: """弹性组件工厂。""" @staticmethod def create_circuit_breaker( name: str, failure_threshold: int = 5, cooldown_seconds: float = 30.0, ) -> CircuitBreaker: return CircuitBreaker( name=name, failure_threshold=failure_threshold, cooldown_seconds=cooldown_seconds, ) @staticmethod def create_retry_strategy( max_retries: int = 3, base_delay: float = 1.0, max_delay: float = 60.0, multiplier: float = 2.0, ) -> RetryStrategy: return RetryStrategy( max_retries=max_retries, base_delay=base_delay, max_delay=max_delay, multiplier=multiplier, )