53 lines
1.6 KiB
Python
53 lines
1.6 KiB
Python
"""
|
||
熔断器 - 每个云端模型独立实例
|
||
|
||
状态机: CLOSED -> OPEN -> HALF_OPEN -> CLOSED/OPEN
|
||
- 连续 threshold 次失败 -> OPEN
|
||
- 冷却 cooldown 秒后 -> HALF_OPEN(允许一次探测)
|
||
- 探测成功 -> CLOSED;探测失败 -> 重新 OPEN
|
||
"""
|
||
from collections import deque
|
||
import time
|
||
import threading
|
||
|
||
|
||
class CircuitBreaker:
|
||
def __init__(self, threshold: int = 5, cooldown: int = 900, enabled: bool = True):
|
||
self.enabled = enabled
|
||
if enabled:
|
||
self.failures = deque(maxlen=threshold)
|
||
else:
|
||
self.failures = None
|
||
self.threshold = threshold
|
||
self.cooldown = cooldown
|
||
self.state = 'CLOSED'
|
||
self.last_failure = None
|
||
self._lock = threading.Lock() # 状态转换加锁,防多线程竞争
|
||
|
||
def record_failure(self):
|
||
if not self.enabled:
|
||
return
|
||
with self._lock:
|
||
self.failures.append(time.time())
|
||
if len(self.failures) >= self.threshold:
|
||
self.state = 'OPEN'
|
||
self.last_failure = time.time()
|
||
|
||
def record_success(self):
|
||
if not self.enabled:
|
||
return
|
||
with self._lock:
|
||
self.failures.clear()
|
||
self.state = 'CLOSED'
|
||
|
||
def is_open(self):
|
||
if not self.enabled:
|
||
return False
|
||
with self._lock:
|
||
if self.state == 'OPEN' and self.last_failure and time.time() - self.last_failure > self.cooldown:
|
||
self.state = 'HALF_OPEN'
|
||
return self.state == 'OPEN'
|
||
|
||
def __repr__(self):
|
||
return f"CircuitBreaker(state={self.state}, enabled={self.enabled})"
|