mirror of
https://github.com/fawney19/Aether.git
synced 2026-01-05 17:22:28 +08:00
206 lines
7.4 KiB
Python
206 lines
7.4 KiB
Python
"""
|
||
提供商健康度管理
|
||
基于简单的失败计数和优先级调整
|
||
"""
|
||
|
||
import time
|
||
from collections import defaultdict
|
||
from datetime import datetime, timedelta
|
||
from typing import Any, Dict, Optional
|
||
|
||
|
||
class ProviderHealthTracker:
|
||
"""
|
||
追踪提供商的健康状态
|
||
根据失败率动态调整优先级
|
||
"""
|
||
|
||
def __init__(
|
||
self,
|
||
failure_window: int = 300, # 5分钟时间窗口
|
||
failure_threshold: int = 3, # 3次失败降低优先级
|
||
recovery_time: int = 600, # 10分钟后重置
|
||
):
|
||
self.failure_window = failure_window
|
||
self.failure_threshold = failure_threshold
|
||
self.recovery_time = recovery_time
|
||
|
||
# 存储每个提供商的失败记录
|
||
self.failures: Dict[str, list] = defaultdict(list)
|
||
# 存储每个提供商的成功记录
|
||
self.successes: Dict[str, list] = defaultdict(list)
|
||
# 存储优先级调整
|
||
self.priority_adjustments: Dict[str, int] = {}
|
||
|
||
def record_success(self, provider_name: str) -> None:
|
||
"""记录成功的请求"""
|
||
current_time = time.time()
|
||
|
||
# 记录成功时间
|
||
self.successes[provider_name].append(current_time)
|
||
|
||
# 清理旧记录
|
||
self._cleanup_old_records(provider_name, current_time)
|
||
|
||
# 如果连续成功,可以恢复优先级
|
||
if len(self.successes[provider_name]) >= 5:
|
||
if self.priority_adjustments.get(provider_name, 0) < 0:
|
||
self.priority_adjustments[provider_name] += 1
|
||
|
||
def record_failure(self, provider_name: str) -> None:
|
||
"""记录失败的请求"""
|
||
current_time = time.time()
|
||
|
||
# 记录失败时间
|
||
self.failures[provider_name].append(current_time)
|
||
|
||
# 清理旧记录
|
||
self._cleanup_old_records(provider_name, current_time)
|
||
|
||
# 检查是否需要降低优先级
|
||
recent_failures = len(self.failures[provider_name])
|
||
if recent_failures >= self.failure_threshold:
|
||
# 降低优先级
|
||
current_adjustment = self.priority_adjustments.get(provider_name, 0)
|
||
self.priority_adjustments[provider_name] = current_adjustment - 1
|
||
|
||
def get_priority_adjustment(self, provider_name: str) -> int:
|
||
"""
|
||
获取优先级调整值
|
||
负数表示降低优先级,正数表示提高优先级
|
||
"""
|
||
return self.priority_adjustments.get(provider_name, 0)
|
||
|
||
def get_health_status(self, provider_name: str) -> Dict:
|
||
"""
|
||
获取提供商的健康状态
|
||
"""
|
||
current_time = time.time()
|
||
self._cleanup_old_records(provider_name, current_time)
|
||
|
||
recent_failures = len(self.failures[provider_name])
|
||
recent_successes = len(self.successes[provider_name])
|
||
total_requests = recent_failures + recent_successes
|
||
|
||
failure_rate = recent_failures / total_requests if total_requests > 0 else 0
|
||
|
||
return {
|
||
"provider": provider_name,
|
||
"recent_failures": recent_failures,
|
||
"recent_successes": recent_successes,
|
||
"failure_rate": failure_rate,
|
||
"priority_adjustment": self.get_priority_adjustment(provider_name),
|
||
"status": self._get_status_label(failure_rate, recent_failures),
|
||
}
|
||
|
||
def _cleanup_old_records(self, provider_name: str, current_time: float) -> None:
|
||
"""清理超出时间窗口的记录"""
|
||
# 清理失败记录
|
||
self.failures[provider_name] = [
|
||
t for t in self.failures[provider_name] if current_time - t < self.failure_window
|
||
]
|
||
|
||
# 清理成功记录
|
||
self.successes[provider_name] = [
|
||
t for t in self.successes[provider_name] if current_time - t < self.failure_window
|
||
]
|
||
|
||
# 如果很久没有失败,重置优先级调整
|
||
if not self.failures[provider_name] and self.priority_adjustments.get(provider_name, 0) < 0:
|
||
# 检查恢复时间
|
||
if all(current_time - t > self.recovery_time for t in self.successes[provider_name]):
|
||
self.priority_adjustments[provider_name] = 0
|
||
|
||
def _get_status_label(self, failure_rate: float, recent_failures: int) -> str:
|
||
"""根据失败率返回状态标签"""
|
||
if recent_failures >= self.failure_threshold:
|
||
return "degraded" # 降级
|
||
elif failure_rate > 0.5:
|
||
return "unstable" # 不稳定
|
||
elif failure_rate > 0.1:
|
||
return "warning" # 警告
|
||
else:
|
||
return "healthy" # 健康
|
||
|
||
def should_use_provider(self, provider_name: str) -> bool:
|
||
"""
|
||
判断是否应该使用该提供商
|
||
简单的策略:如果优先级调整低于-3,暂时不使用
|
||
"""
|
||
adjustment = self.get_priority_adjustment(provider_name)
|
||
return adjustment > -3
|
||
|
||
def reset_provider_health(self, provider_name: str) -> None:
|
||
"""重置提供商的健康状态(管理员手动操作)"""
|
||
self.failures[provider_name] = []
|
||
self.successes[provider_name] = []
|
||
self.priority_adjustments[provider_name] = 0
|
||
|
||
|
||
class SimpleProviderSelector:
|
||
"""
|
||
简单的提供商选择器
|
||
基于优先级和健康状态
|
||
"""
|
||
|
||
def __init__(self, health_tracker: ProviderHealthTracker):
|
||
self.health_tracker = health_tracker
|
||
|
||
def select_provider(self, providers: list, specified_provider: Optional[str] = None) -> Any:
|
||
"""
|
||
选择提供商
|
||
|
||
Args:
|
||
providers: 可用提供商列表(已按基础优先级排序)
|
||
specified_provider: 用户指定的提供商
|
||
|
||
Returns:
|
||
选中的提供商
|
||
"""
|
||
# 如果用户指定了提供商,直接使用(不管健康状态)
|
||
if specified_provider:
|
||
return next((p for p in providers if p.name == specified_provider), None)
|
||
|
||
# 否则,根据优先级和健康状态选择
|
||
# 对提供商列表进行动态排序
|
||
sorted_providers = sorted(
|
||
providers,
|
||
key=lambda p: (
|
||
p.priority + self.health_tracker.get_priority_adjustment(p.name),
|
||
-p.id, # 相同优先级时,使用ID作为次要排序
|
||
),
|
||
reverse=True, # 优先级高的在前
|
||
)
|
||
|
||
# 选择第一个健康的提供商
|
||
for provider in sorted_providers:
|
||
if self.health_tracker.should_use_provider(provider.name):
|
||
return provider
|
||
|
||
# 如果都不健康,还是返回第一个(降级策略)
|
||
return sorted_providers[0] if sorted_providers else None
|
||
|
||
def get_provider_rankings(self, providers: list) -> list:
|
||
"""
|
||
获取提供商的当前排名(用于调试和监控)
|
||
"""
|
||
rankings = []
|
||
for provider in providers:
|
||
health_status = self.health_tracker.get_health_status(provider.name)
|
||
effective_priority = provider.priority + health_status["priority_adjustment"]
|
||
|
||
rankings.append(
|
||
{
|
||
"name": provider.name,
|
||
"base_priority": provider.priority,
|
||
"adjustment": health_status["priority_adjustment"],
|
||
"effective_priority": effective_priority,
|
||
"status": health_status["status"],
|
||
"failure_rate": health_status["failure_rate"],
|
||
}
|
||
)
|
||
|
||
# 按有效优先级排序
|
||
rankings.sort(key=lambda x: x["effective_priority"], reverse=True)
|
||
return rankings
|