PYTHON实现智能API请求重试与熔断机制
·
import requests
import time
from typing import Callable, Optional
from dataclasses import dataclass
from datetime import datetime, timedelta
import math
@dataclass
class CircuitBreakerState:
"""熔断器状态"""
failures: int = 0
last_failure_time: Optional[datetime] = None
is_open: bool = False
next_attempt_time: Optional[datetime] = None
class APIClientWithRetry:
"""带重试和熔断机制的API客户端"""
def __init__(
self,
max_retries: int = 3,
backoff_factor: float = 0.5,
failure_threshold: int = 5,
reset_timeout: timedelta = timedelta(seconds=30)
):
"""
参数:
max_retries: 最大重试次数
backoff_factor: 指数退避因子
failure_threshold: 熔断触发阈值
reset_timeout: 熔断恢复时间
"""
self.max_retries = max_retries
self.backoff_factor = backoff_factor
self.failure_threshold = failure_threshold
self.reset_timeout = reset_timeout
self.circuit_breaker = CircuitBreakerState()
self.session = requests.Session()
def _calculate_backoff(self, retry_count: int) -> float:
"""计算指数退避时间"""
return self.backoff_factor * (2 ** (retry_count - 1))
def _should_retry(self, status_code: int) -> bool:
"""判断是否需要重试"""
return status_code >= 500 or status_code == 429
def _update_circuit_breaker(self, success: bool):
"""更新熔断器状态"""
now = datetime.now()
if success:
if self.circuit_breaker.is_open:
# 熔断状态下成功请求,关闭熔断器
self.circuit_breaker.is_open = False
self.circuit_breaker.failures = 0
return
# 请求失败,更新状态
self.circuit_breaker.failures += 1
self.circuit_breaker.last_failure_time = now
# 检查是否触发熔断
if (self.circuit_breaker.failures >= self.failure_threshold and
not self.circuit_breaker.is_open):
self.circuit_breaker.is_open = True
self.circuit_breaker.next_attempt_time = now + self.reset_timeout
def request_with_retry(
self,
method: str,
url: str,
**kwargs
) -> requests.Response:
"""带重试和熔断机制的请求方法"""
# 检查熔断状态
if self.circuit_breaker.is_open:
if datetime.now() < self.circuit_breaker.next_attempt_time:
raise Exception(f"Circuit breaker open until {self.circuit_breaker.next_attempt_time}")
# 尝试恢复
self.circuit_breaker.is_open = False
last_exception = None
for attempt in range(self.max_retries + 1):
try:
response = self.session.request(method, url, **kwargs)
if not self._should_retry(response.status_code):
self._update_circuit_breaker(True)
return response
# 需要重试的情况
if attempt == self.max_retries:
self._update_circuit_breaker(False)
return response
except Exception as e:
last_exception = e
if attempt == self.max_retries:
self._update_circuit_breaker(False)
raise
# 计算并等待退避时间
backoff = self._calculate_backoff(attempt + 1)
time.sleep(backoff)
self._update_circuit_breaker(False)
raise last_exception or Exception("Unknown error occurred")
# 示例使用
if __name__ == "__main__":
client = APIClientWithRetry(
max_retries=3,
backoff_factor=0.5,
failure_threshold=3,
reset_timeout=timedelta(seconds=10)
)
try:
response = client.request_with_retry(
"GET",
"https://api.example.com/data",
timeout=5
)
print("请求成功:", response.status_code)
except Exception as e:
print("请求失败:", str(e))
使用说明
-
功能特点:
- 自动重试失败的API请求(针对5xx和429状态码)
- 指数退避算法避免请求风暴
- 熔断机制防止连续失败
- 自动恢复机制
- 线程安全的请求会话
-
核心参数:
max_retries: 最大重试次数(默认3)backoff_factor: 退避因子(默认0.5秒)failure_threshold: 熔断触发阈值(默认5次失败)reset_timeout: 熔断恢复时间(默认30秒)
-
使用方法:
# 初始化客户端 client = APIClientWithRetry( max_retries=3, backoff_factor=0.5 ) # 发送请求 try: response = client.request_with_retry( "GET", "https://api.example.com/data", params={"key": "value"}, headers={"Authorization": "Bearer token"} ) print(response.json()) except Exception as e: print("请求最终失败:", e) -
应用场景:
- 调用不稳定第三方API
- 微服务间通信
- 高并发请求处理
- 需要高可靠性的API调用
-
注意事项:
- 非幂等操作(POST/PUT/DELETE)慎用
- 熔断期间所有请求会被拒绝
- 退避时间随重试次数指数增长
- 生产环境建议添加监控指标
更多推荐



所有评论(0)