mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 01:10:23 +08:00
refactor: 移除 Python 后端源码,全面迁移至 Rust gateway 架构
- 删除全部 Python 源码 (src/) 及 Alembic 迁移脚本,归档至 _deprecated_py_src/ - 重构 Rust gateway ai_pipeline: 拆分 planner/finalize 模块,新增 contracts/adaptation 层 - 重组 handlers 模块为 admin/public/proxy/internal/shared 子模块结构 - 新增 executor 模块,引入 Rust 原生数据库迁移 (aether-data/migrations) - 简化 CI/Docker 构建流程,移除 base image 二级构建,统一为单一 app image - 移除 Python 相关基础设施文件 (entrypoint.sh, gunicorn_conf.py, Dockerfile.base)
This commit is contained in:
13
_deprecated_py_src/plugins/load_balancer/__init__.py
Normal file
13
_deprecated_py_src/plugins/load_balancer/__init__.py
Normal file
@@ -0,0 +1,13 @@
|
||||
"""
|
||||
负载均衡策略插件
|
||||
"""
|
||||
|
||||
from .base import LoadBalancerStrategy, ProviderCandidate, SelectionResult
|
||||
from .sticky_priority import StickyPriorityStrategy
|
||||
|
||||
__all__ = [
|
||||
"LoadBalancerStrategy",
|
||||
"ProviderCandidate",
|
||||
"SelectionResult",
|
||||
"StickyPriorityStrategy",
|
||||
]
|
||||
145
_deprecated_py_src/plugins/load_balancer/base.py
Normal file
145
_deprecated_py_src/plugins/load_balancer/base.py
Normal file
@@ -0,0 +1,145 @@
|
||||
"""
|
||||
负载均衡策略基类
|
||||
定义负载均衡策略的接口
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import abstractmethod
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
from ..common import BasePlugin
|
||||
|
||||
|
||||
@dataclass
|
||||
class ProviderCandidate:
|
||||
"""
|
||||
候选提供商信息
|
||||
"""
|
||||
|
||||
provider: Any # Provider 对象
|
||||
priority: int = 0 # 优先级(数字越大优先级越高)
|
||||
weight: float = 1.0 # 权重(影响被选中的概率)
|
||||
model: Any | None = None # Model 对象(如果需要模型信息)
|
||||
metadata: dict[str, Any] | None = None # 额外元数据
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if self.metadata is None:
|
||||
self.metadata = {}
|
||||
|
||||
def __lt__(self, other: object) -> bool:
|
||||
if not isinstance(other, ProviderCandidate):
|
||||
return NotImplemented
|
||||
# 优先级数字越大越优先,权重越大越优先
|
||||
return (-self.priority, -self.weight, str(getattr(self.provider, "id", ""))) < (
|
||||
-other.priority,
|
||||
-other.weight,
|
||||
str(getattr(other.provider, "id", "")),
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class SelectionResult:
|
||||
"""
|
||||
选择结果
|
||||
"""
|
||||
|
||||
provider: Any # 选中的提供商
|
||||
priority: int # 该提供商的优先级
|
||||
weight: float # 该提供商的权重
|
||||
selection_metadata: dict[str, Any] | None = None # 选择过程的元数据
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if self.selection_metadata is None:
|
||||
self.selection_metadata = {}
|
||||
|
||||
|
||||
class LoadBalancerStrategy(BasePlugin):
|
||||
"""
|
||||
负载均衡策略基类
|
||||
所有负载均衡策略必须继承此类
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
priority: int = 0,
|
||||
version: str = "1.0.0",
|
||||
author: str = "Unknown",
|
||||
description: str = "",
|
||||
api_version: str = "1.0",
|
||||
dependencies: list[str] | None = None,
|
||||
provides: list[str] | None = None,
|
||||
config: dict[str, Any] | None = None,
|
||||
):
|
||||
"""
|
||||
初始化负载均衡策略
|
||||
|
||||
Args:
|
||||
name: 策略名称
|
||||
priority: 优先级(数字越大优先级越高)
|
||||
version: 插件版本
|
||||
author: 插件作者
|
||||
description: 插件描述
|
||||
api_version: API版本
|
||||
dependencies: 依赖的其他插件
|
||||
provides: 提供的服务
|
||||
config: 配置字典
|
||||
"""
|
||||
super().__init__(
|
||||
name=name,
|
||||
priority=priority,
|
||||
version=version,
|
||||
author=author,
|
||||
description=description,
|
||||
api_version=api_version,
|
||||
dependencies=dependencies,
|
||||
provides=provides,
|
||||
config=config,
|
||||
)
|
||||
|
||||
@abstractmethod
|
||||
async def select(
|
||||
self, candidates: list[ProviderCandidate], context: dict[str, Any] | None = None
|
||||
) -> SelectionResult | None:
|
||||
"""
|
||||
从候选提供商中选择一个
|
||||
|
||||
Args:
|
||||
candidates: 候选提供商列表
|
||||
context: 上下文信息(如请求ID、用户信息等)
|
||||
|
||||
Returns:
|
||||
选择结果,如果没有可用提供商则返回 None
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def get_stats(self) -> dict[str, Any]:
|
||||
"""
|
||||
获取负载均衡统计信息
|
||||
|
||||
Returns:
|
||||
统计信息字典
|
||||
"""
|
||||
pass
|
||||
|
||||
async def record_result(
|
||||
self,
|
||||
provider: Any,
|
||||
success: bool,
|
||||
response_time: float | None = None,
|
||||
error: Exception | None = None,
|
||||
) -> Any:
|
||||
"""
|
||||
记录请求结果(用于动态调整策略)
|
||||
|
||||
Args:
|
||||
provider: 提供商对象
|
||||
success: 是否成功
|
||||
response_time: 响应时间(秒)
|
||||
error: 错误信息(如果失败)
|
||||
"""
|
||||
# 默认实现为空,子类可以重写来实现动态调整
|
||||
pass
|
||||
474
_deprecated_py_src/plugins/load_balancer/sticky_priority.py
Normal file
474
_deprecated_py_src/plugins/load_balancer/sticky_priority.py
Normal file
@@ -0,0 +1,474 @@
|
||||
"""
|
||||
粘性优先级负载均衡策略
|
||||
正常情况下始终选择同一个提供商(优先级最高+权重最大),只在故障时切换
|
||||
|
||||
WARNING: 多进程环境注意事项
|
||||
=============================
|
||||
此插件的健康状态和粘性缓存存储在进程内存中。如果使用 Gunicorn/uvicorn 多 worker 模式,
|
||||
每个 worker 进程有独立的状态,可能导致:
|
||||
- 不同 worker 看到的提供商健康状态不同
|
||||
- 粘性路由在不同 worker 间不一致
|
||||
- 统计数据分散在各个 worker 中
|
||||
|
||||
解决方案:
|
||||
1. 单 worker 模式:适用于低流量场景
|
||||
2. Redis 共享状态:将 _provider_health 和 _sticky_providers 迁移到 Redis
|
||||
3. 使用独立的健康检查服务:所有 worker 共享同一个健康状态源
|
||||
|
||||
目前项目已有 Redis 依赖,建议在高可用场景下将状态迁移到 Redis。
|
||||
参考:src/services/health/monitor.py 中的实现
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
from collections import defaultdict
|
||||
from typing import Any
|
||||
|
||||
from src.core.logger import logger
|
||||
|
||||
from .base import LoadBalancerStrategy, ProviderCandidate, SelectionResult
|
||||
|
||||
|
||||
class StickyPriorityStrategy(LoadBalancerStrategy):
|
||||
"""
|
||||
粘性优先级策略
|
||||
|
||||
选择逻辑:
|
||||
1. 在最高优先级组中,选择权重最大的提供商作为"粘性"提供商
|
||||
2. 正常情况下,始终选择该粘性提供商
|
||||
3. 只有在粘性提供商失败时,才切换到同优先级的其他提供商
|
||||
4. 当粘性提供商恢复后,自动切回
|
||||
|
||||
特点:
|
||||
- 最小化提供商切换,流量集中在单一提供商
|
||||
- 自动故障转移和恢复
|
||||
- 适合需要集中使用某个API Key的场景
|
||||
|
||||
Note:
|
||||
状态存储在进程内存中,多进程部署时各 worker 状态独立。
|
||||
详见模块文档说明。
|
||||
"""
|
||||
|
||||
def __init__(self, config: dict[str, Any] | None = None):
|
||||
config = config or {} # 确保 config 不为 None
|
||||
super().__init__(
|
||||
name="sticky_priority",
|
||||
priority=110, # 比默认的 priority_weighted 更高
|
||||
version="1.0.0",
|
||||
author="System",
|
||||
description="粘性优先级负载均衡策略,正常时始终使用同一提供商",
|
||||
api_version="1.0",
|
||||
provides=["load_balancer"],
|
||||
config=config,
|
||||
)
|
||||
|
||||
# 配置参数
|
||||
self.failure_threshold = config.get("failure_threshold", 3) # 连续失败阈值
|
||||
self.recovery_delay = config.get("recovery_delay", 30) # 恢复延迟(秒)
|
||||
self.enable_auto_recovery = config.get("enable_auto_recovery", True) # 是否自动恢复
|
||||
|
||||
# 提供商健康状态追踪 {provider_id: health_info}
|
||||
self._provider_health: dict[str, dict[str, Any]] = defaultdict(
|
||||
lambda: {
|
||||
"consecutive_failures": 0,
|
||||
"last_failure_time": None,
|
||||
"is_healthy": True,
|
||||
"total_requests": 0,
|
||||
"total_failures": 0,
|
||||
}
|
||||
)
|
||||
self._max_provider_health_entries: int = 200 # 上限,防止无界增长
|
||||
|
||||
# 当前粘性提供商缓存 {cache_key: provider_id}
|
||||
# cache_key 可以是 api_key_id 或者其他标识
|
||||
self._sticky_providers: dict[str, str] = {}
|
||||
self._max_sticky_entries: int = 2000 # 上限,防止无界增长
|
||||
|
||||
# 统计信息
|
||||
self._stats = {
|
||||
"total_selections": 0,
|
||||
"provider_selections": {},
|
||||
"sticky_hits": 0, # 选择粘性提供商的次数
|
||||
"failovers": 0, # 故障切换次数
|
||||
"auto_recoveries": 0, # 自动恢复次数
|
||||
}
|
||||
|
||||
async def select(
|
||||
self, candidates: list[ProviderCandidate], context: dict[str, Any] | None = None
|
||||
) -> SelectionResult | None:
|
||||
"""
|
||||
从候选提供商中选择一个
|
||||
|
||||
Args:
|
||||
candidates: 候选提供商列表
|
||||
context: 上下文信息(包含 api_key_id 等)
|
||||
|
||||
Returns:
|
||||
选择结果
|
||||
"""
|
||||
if not candidates:
|
||||
logger.warning("No candidates available for selection")
|
||||
return None
|
||||
|
||||
if len(candidates) == 1:
|
||||
candidate = candidates[0]
|
||||
self._record_selection(candidate.provider, is_sticky=True)
|
||||
return SelectionResult(
|
||||
provider=candidate.provider,
|
||||
priority=candidate.priority,
|
||||
weight=candidate.weight,
|
||||
selection_metadata={"strategy": "single_candidate"},
|
||||
)
|
||||
|
||||
# 获取缓存键(用于识别同一请求源)
|
||||
cache_key = self._get_cache_key(context)
|
||||
|
||||
# 按优先级分组
|
||||
priority_groups = self._group_by_priority(candidates)
|
||||
highest_priority = max(priority_groups.keys())
|
||||
highest_group = priority_groups[highest_priority]
|
||||
|
||||
# 确定粘性提供商
|
||||
sticky_candidate = self._determine_sticky_provider(highest_group, cache_key, context)
|
||||
|
||||
# 检查粘性提供商是否健康
|
||||
provider_id = str(sticky_candidate.provider.id)
|
||||
health_info = self._provider_health[provider_id]
|
||||
|
||||
# 如果粘性提供商健康,直接使用
|
||||
if health_info["is_healthy"]:
|
||||
self._record_selection(sticky_candidate.provider, is_sticky=True)
|
||||
|
||||
logger.info(f"Selected sticky provider {sticky_candidate.provider.name}")
|
||||
|
||||
return SelectionResult(
|
||||
provider=sticky_candidate.provider,
|
||||
priority=sticky_candidate.priority,
|
||||
weight=sticky_candidate.weight,
|
||||
selection_metadata={
|
||||
"strategy": "sticky_priority",
|
||||
"is_sticky": True,
|
||||
"cache_key": cache_key,
|
||||
"health_status": "healthy",
|
||||
},
|
||||
)
|
||||
|
||||
# 粘性提供商不健康,选择备用提供商
|
||||
logger.warning(
|
||||
f"Sticky provider {sticky_candidate.provider.name} is unhealthy, selecting backup"
|
||||
)
|
||||
|
||||
# 从同一优先级组中选择健康的备用提供商
|
||||
backup_candidate = self._select_backup_provider(highest_group)
|
||||
|
||||
if not backup_candidate:
|
||||
# 如果没有健康的备用,降级使用不健康的粘性提供商
|
||||
logger.warning(
|
||||
"No healthy backup provider available, falling back to unhealthy sticky provider"
|
||||
)
|
||||
backup_candidate = sticky_candidate
|
||||
|
||||
self._record_selection(backup_candidate.provider, is_sticky=False)
|
||||
self._stats["failovers"] += 1
|
||||
|
||||
logger.info(f"Selected backup provider {backup_candidate.provider.name}")
|
||||
|
||||
return SelectionResult(
|
||||
provider=backup_candidate.provider,
|
||||
priority=backup_candidate.priority,
|
||||
weight=backup_candidate.weight,
|
||||
selection_metadata={
|
||||
"strategy": "sticky_priority",
|
||||
"is_sticky": False,
|
||||
"is_failover": True,
|
||||
"original_provider_id": provider_id,
|
||||
"health_status": "backup",
|
||||
},
|
||||
)
|
||||
|
||||
def _get_cache_key(self, context: dict[str, Any] | None) -> str:
|
||||
"""
|
||||
生成缓存键,用于识别同一请求源
|
||||
|
||||
Args:
|
||||
context: 上下文信息
|
||||
|
||||
Returns:
|
||||
缓存键
|
||||
"""
|
||||
if not context:
|
||||
return "default"
|
||||
|
||||
# 优先使用 api_key_id
|
||||
if "api_key_id" in context:
|
||||
return f"api_key_{context['api_key_id']}"
|
||||
|
||||
# 其他标识
|
||||
if "user_id" in context:
|
||||
return f"user_{context['user_id']}"
|
||||
|
||||
return "default"
|
||||
|
||||
def _group_by_priority(
|
||||
self, candidates: list[ProviderCandidate]
|
||||
) -> dict[int, list[ProviderCandidate]]:
|
||||
"""按优先级分组候选提供商"""
|
||||
groups: dict[int, list[ProviderCandidate]] = {}
|
||||
for candidate in candidates:
|
||||
priority = candidate.priority
|
||||
if priority not in groups:
|
||||
groups[priority] = []
|
||||
groups[priority].append(candidate)
|
||||
return groups
|
||||
|
||||
def _determine_sticky_provider(
|
||||
self,
|
||||
candidates: list[ProviderCandidate],
|
||||
cache_key: str,
|
||||
context: dict[str, Any] | None = None,
|
||||
) -> ProviderCandidate:
|
||||
"""
|
||||
确定粘性提供商
|
||||
|
||||
策略:
|
||||
1. 如果已有缓存的粘性提供商,检查是否仍在候选列表中
|
||||
2. 如果没有或已失效,选择权重最大的作为新的粘性提供商
|
||||
|
||||
Args:
|
||||
candidates: 同一优先级的候选列表
|
||||
cache_key: 缓存键
|
||||
context: 上下文信息
|
||||
|
||||
Returns:
|
||||
粘性提供商候选
|
||||
"""
|
||||
# 检查缓存的粘性提供商
|
||||
if cache_key in self._sticky_providers:
|
||||
cached_provider_id = self._sticky_providers[cache_key]
|
||||
|
||||
# 查找是否仍在候选列表中
|
||||
for candidate in candidates:
|
||||
if str(candidate.provider.id) == cached_provider_id:
|
||||
# 检查是否可以自动恢复
|
||||
if self._can_auto_recover(cached_provider_id):
|
||||
logger.info(f"Auto-recovering sticky provider {candidate.provider.name}")
|
||||
self._stats["auto_recoveries"] += 1
|
||||
# 重置健康状态
|
||||
self._provider_health[cached_provider_id]["is_healthy"] = True
|
||||
self._provider_health[cached_provider_id]["consecutive_failures"] = 0
|
||||
|
||||
return candidate
|
||||
|
||||
# 没有缓存或缓存失效,选择权重最大的
|
||||
sticky_candidate = max(candidates, key=lambda c: c.weight)
|
||||
# 超出上限时清理不在当前候选列表中的旧条目
|
||||
if len(self._sticky_providers) >= self._max_sticky_entries:
|
||||
active_ids = {str(c.provider.id) for c in candidates}
|
||||
stale = [k for k, v in self._sticky_providers.items() if v not in active_ids]
|
||||
for k in stale[: len(stale) // 2 or len(stale)]:
|
||||
del self._sticky_providers[k]
|
||||
self._sticky_providers[cache_key] = str(sticky_candidate.provider.id)
|
||||
|
||||
logger.info(f"Set new sticky provider {sticky_candidate.provider.name}")
|
||||
|
||||
return sticky_candidate
|
||||
|
||||
def _can_auto_recover(self, provider_id: str) -> bool:
|
||||
"""
|
||||
检查提供商是否可以自动恢复
|
||||
|
||||
Args:
|
||||
provider_id: 提供商ID
|
||||
|
||||
Returns:
|
||||
是否可以恢复
|
||||
"""
|
||||
if not self.enable_auto_recovery:
|
||||
return False
|
||||
|
||||
health_info = self._provider_health[provider_id]
|
||||
|
||||
# 如果已经是健康状态,直接返回 True
|
||||
if health_info["is_healthy"]:
|
||||
return True
|
||||
|
||||
# 检查是否超过恢复延迟
|
||||
if health_info["last_failure_time"]:
|
||||
time_since_failure = time.time() - health_info["last_failure_time"]
|
||||
if time_since_failure >= self.recovery_delay:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _select_backup_provider(
|
||||
self, candidates: list[ProviderCandidate]
|
||||
) -> ProviderCandidate | None:
|
||||
"""
|
||||
从候选列表中选择健康的备用提供商
|
||||
|
||||
优先选择权重最大且健康的提供商
|
||||
|
||||
Args:
|
||||
candidates: 候选提供商列表
|
||||
|
||||
Returns:
|
||||
备用提供商,如果没有健康的则返回 None
|
||||
"""
|
||||
healthy_candidates = []
|
||||
|
||||
for candidate in candidates:
|
||||
provider_id = str(candidate.provider.id)
|
||||
health_info = self._provider_health[provider_id]
|
||||
|
||||
# 检查是否可以自动恢复
|
||||
if health_info["is_healthy"] or self._can_auto_recover(provider_id):
|
||||
if not health_info["is_healthy"]:
|
||||
# 自动恢复
|
||||
health_info["is_healthy"] = True
|
||||
health_info["consecutive_failures"] = 0
|
||||
self._stats["auto_recoveries"] += 1
|
||||
|
||||
healthy_candidates.append(candidate)
|
||||
|
||||
if not healthy_candidates:
|
||||
return None
|
||||
|
||||
# 选择权重最大的健康提供商
|
||||
return max(healthy_candidates, key=lambda c: c.weight)
|
||||
|
||||
def _record_selection(self, provider: Any, is_sticky: bool = True) -> None:
|
||||
"""记录选择统计"""
|
||||
self._stats["total_selections"] += 1
|
||||
provider_id = str(provider.id)
|
||||
|
||||
if provider_id not in self._stats["provider_selections"]:
|
||||
self._stats["provider_selections"][provider_id] = 0
|
||||
self._stats["provider_selections"][provider_id] += 1
|
||||
|
||||
if is_sticky:
|
||||
self._stats["sticky_hits"] += 1
|
||||
|
||||
async def record_result(
|
||||
self,
|
||||
provider: Any,
|
||||
success: bool,
|
||||
response_time: float | None = None,
|
||||
error: Exception | None = None,
|
||||
) -> Any:
|
||||
"""
|
||||
记录请求结果,更新健康状态
|
||||
|
||||
Args:
|
||||
provider: 提供商对象
|
||||
success: 是否成功
|
||||
response_time: 响应时间(秒)
|
||||
error: 错误信息(如果失败)
|
||||
"""
|
||||
provider_id = str(provider.id)
|
||||
# 超出上限时淘汰健康且请求量最少的条目
|
||||
if (
|
||||
provider_id not in self._provider_health
|
||||
and len(self._provider_health) >= self._max_provider_health_entries
|
||||
):
|
||||
healthy_keys = [
|
||||
k for k, v in self._provider_health.items() if v["is_healthy"] and k != provider_id
|
||||
]
|
||||
if healthy_keys:
|
||||
victim = min(healthy_keys, key=lambda k: self._provider_health[k]["total_requests"])
|
||||
del self._provider_health[victim]
|
||||
health_info = self._provider_health[provider_id]
|
||||
|
||||
health_info["total_requests"] += 1
|
||||
|
||||
if success:
|
||||
# 成功,重置连续失败计数
|
||||
health_info["consecutive_failures"] = 0
|
||||
health_info["is_healthy"] = True
|
||||
|
||||
logger.debug(f"Recorded successful result for provider {provider.name}")
|
||||
else:
|
||||
# 失败,增加连续失败计数
|
||||
health_info["consecutive_failures"] += 1
|
||||
health_info["total_failures"] += 1
|
||||
health_info["last_failure_time"] = time.time()
|
||||
|
||||
# 检查是否达到失败阈值
|
||||
if health_info["consecutive_failures"] >= self.failure_threshold:
|
||||
health_info["is_healthy"] = False
|
||||
|
||||
logger.warning(f"Provider {provider.name} marked as unhealthy")
|
||||
else:
|
||||
logger.debug(f"Recorded failed result for provider {provider.name}")
|
||||
|
||||
async def get_stats(self) -> dict[str, Any]:
|
||||
"""获取统计信息"""
|
||||
# 计算健康状态
|
||||
healthy_count = sum(1 for info in self._provider_health.values() if info["is_healthy"])
|
||||
|
||||
total_providers = len(self._provider_health)
|
||||
|
||||
# 计算粘性命中率
|
||||
sticky_hit_rate = 0.0
|
||||
if self._stats["total_selections"] > 0:
|
||||
sticky_hit_rate = self._stats["sticky_hits"] / self._stats["total_selections"]
|
||||
|
||||
return {
|
||||
"strategy": "sticky_priority",
|
||||
"total_selections": self._stats["total_selections"],
|
||||
"provider_selections": self._stats["provider_selections"],
|
||||
"sticky_hits": self._stats["sticky_hits"],
|
||||
"sticky_hit_rate": sticky_hit_rate,
|
||||
"failovers": self._stats["failovers"],
|
||||
"auto_recoveries": self._stats["auto_recoveries"],
|
||||
"healthy_providers": healthy_count,
|
||||
"total_providers": total_providers,
|
||||
"provider_health": {
|
||||
provider_id: {
|
||||
"is_healthy": info["is_healthy"],
|
||||
"consecutive_failures": info["consecutive_failures"],
|
||||
"total_requests": info["total_requests"],
|
||||
"total_failures": info["total_failures"],
|
||||
"failure_rate": (
|
||||
info["total_failures"] / info["total_requests"]
|
||||
if info["total_requests"] > 0
|
||||
else 0
|
||||
),
|
||||
"last_failure_time": info["last_failure_time"],
|
||||
}
|
||||
for provider_id, info in self._provider_health.items()
|
||||
},
|
||||
"sticky_providers": self._sticky_providers,
|
||||
"config": {
|
||||
"failure_threshold": self.failure_threshold,
|
||||
"recovery_delay": self.recovery_delay,
|
||||
"enable_auto_recovery": self.enable_auto_recovery,
|
||||
},
|
||||
}
|
||||
|
||||
async def reset_provider_health(self, provider_id: str) -> None:
|
||||
"""重置指定提供商的健康状态"""
|
||||
if provider_id in self._provider_health:
|
||||
self._provider_health[provider_id] = {
|
||||
"consecutive_failures": 0,
|
||||
"last_failure_time": None,
|
||||
"is_healthy": True,
|
||||
"total_requests": 0,
|
||||
"total_failures": 0,
|
||||
}
|
||||
logger.info(f"Reset health status for provider {provider_id}")
|
||||
|
||||
async def clear_sticky_cache(self, cache_key: str | None = None) -> None:
|
||||
"""
|
||||
清除粘性提供商缓存
|
||||
|
||||
Args:
|
||||
cache_key: 指定要清除的缓存键,None 则清除全部
|
||||
"""
|
||||
if cache_key:
|
||||
if cache_key in self._sticky_providers:
|
||||
del self._sticky_providers[cache_key]
|
||||
logger.info(f"Cleared sticky provider cache for key: {cache_key}")
|
||||
else:
|
||||
self._sticky_providers.clear()
|
||||
logger.info("Cleared all sticky provider cache")
|
||||
Reference in New Issue
Block a user