chore: 升级到 Python 3.14 并现代化代码

- 升级 Docker 基础镜像从 Python 3.12 到 3.14
- 更新 pyproject.toml 支持 Python 3.13/3.14
- 移除 Python 3.8/3.9/3.10/3.11 分类器
- 更新 black 和 mypy 配置目标版本
- 将 get_event_loop() 替换为 get_running_loop() 加上 RuntimeError 处理
- 简化 compute_cost_sync 中的 asyncio.run 使用
- Dict/List/Tuple/Set → dict/list/tuple/set (PEP 585)
- Optional[T] → T | None (PEP 604)
- Union[A, B] → A | B (PEP 604)
- 移除废弃的 typing 导入
- 移除不必要的字符串引号注解
This commit is contained in:
AAEE86
2026-01-30 03:10:21 +08:00
parent 3e75bc8964
commit 24d24f6829
255 changed files with 4062 additions and 4173 deletions

View File

@@ -23,7 +23,7 @@ import json
import os
import time
from contextlib import asynccontextmanager
from typing import Any, Dict, List, NamedTuple, Optional, Tuple
from typing import Any, NamedTuple
from src.config.constants import CacheTTL
from src.core.logger import logger
@@ -86,18 +86,18 @@ class CacheAffinityManager:
"""
self.redis = redis_client
self.default_ttl = default_ttl
self._memory_store: Dict[str, Dict[str, Any]] = {}
self._memory_lock: Optional[asyncio.Lock] = None
self._memory_store: dict[str, dict[str, Any]] = {}
self._memory_lock: asyncio.Lock | None = None
# L1 缓存(即使使用 Redis 也启用,减少网络往返)
self._l1_cache_ttl = int(os.getenv("CACHE_AFFINITY_L1_TTL", str(CacheTTL.L1_LOCAL)))
self._l1_cache: Dict[str, Tuple[float, Dict[str, Any]]] = {}
self._l1_cache: dict[str, tuple[float, dict[str, Any]]] = {}
self._l1_lock = asyncio.Lock()
self._l1_max_size = int(os.getenv("CACHE_AFFINITY_L1_MAX_SIZE", "1000")) # 最大缓存条目数
self._l1_last_cleanup = time.time()
# 请求级别锁,避免同一用户+端点同时更新造成抖动
self._request_locks: Dict[str, asyncio.Lock] = {}
self._request_locks: dict[str, asyncio.Lock] = {}
# 统计信息
self._stats = {
@@ -138,7 +138,7 @@ class CacheAffinityManager:
"""
return f"cache_affinity:{affinity_key}:{api_format}:{model_name}"
async def _get_l1_entry(self, cache_key: str) -> Optional[Dict[str, Any]]:
async def _get_l1_entry(self, cache_key: str) -> dict[str, Any] | None:
async with self._l1_lock:
record = self._l1_cache.get(cache_key)
if not record:
@@ -149,7 +149,7 @@ class CacheAffinityManager:
return None
return dict(payload)
async def _set_l1_entry(self, cache_key: str, payload: Optional[Dict[str, Any]]):
async def _set_l1_entry(self, cache_key: str, payload: dict[str, Any] | None):
async with self._l1_lock:
if not payload:
self._l1_cache.pop(cache_key, None)
@@ -205,7 +205,7 @@ class CacheAffinityManager:
finally:
lock.release()
async def _load_affinity_dict(self, cache_key: str) -> Optional[Dict[str, Any]]:
async def _load_affinity_dict(self, cache_key: str) -> dict[str, Any] | None:
"""读取缓存亲和性字典"""
# 先尝试L1缓存
l1_value = await self._get_l1_entry(cache_key)
@@ -228,7 +228,7 @@ class CacheAffinityManager:
return dict(record) if record else None
async def _save_affinity_dict(
self, cache_key: str, ttl: int, affinity_dict: Dict[str, Any]
self, cache_key: str, ttl: int, affinity_dict: dict[str, Any]
) -> None:
"""存储缓存亲和性字典"""
if not self._is_memory_backend():
@@ -252,7 +252,7 @@ class CacheAffinityManager:
await self._set_l1_entry(cache_key, None)
async def _snapshot_memory_items(self) -> Dict[str, Dict[str, Any]]:
async def _snapshot_memory_items(self) -> dict[str, dict[str, Any]]:
"""复制内存存储内容(仅内存模式使用)"""
lock = self._get_memory_lock()
async with lock:
@@ -260,7 +260,7 @@ class CacheAffinityManager:
async def get_affinity(
self, affinity_key: str, api_format: str, model_name: str
) -> Optional[CacheAffinity]:
) -> CacheAffinity | None:
"""
获取指定亲和性标识符对特定API格式和模型的缓存亲和性
@@ -315,7 +315,7 @@ class CacheAffinityManager:
api_format: str,
model_name: str,
supports_caching: bool = True,
ttl: Optional[int] = None,
ttl: int | None = None,
) -> None:
"""
设置指定亲和性标识符对特定API格式和模型的缓存亲和性
@@ -345,7 +345,7 @@ class CacheAffinityManager:
try:
async with self._acquire_request_lock(cache_key):
existing_dict = await self._load_affinity_dict(cache_key)
existing_affinity: Optional[CacheAffinity] = None
existing_affinity: CacheAffinity | None = None
if existing_dict and current_time <= existing_dict.get("expire_at", 0):
existing_affinity = CacheAffinity(
provider_id=existing_dict["provider_id"],
@@ -408,9 +408,9 @@ class CacheAffinityManager:
affinity_key: str,
api_format: str,
model_name: str,
key_id: Optional[str] = None,
provider_id: Optional[str] = None,
endpoint_id: Optional[str] = None,
key_id: str | None = None,
provider_id: str | None = None,
endpoint_id: str | None = None,
) -> None:
"""
失效指定亲和性标识符对特定API格式和模型的缓存亲和性
@@ -527,7 +527,7 @@ class CacheAffinityManager:
logger.exception(f"清除缓存亲和性失败: {e}")
return 0
def get_stats(self) -> Dict[str, Any]:
def get_stats(self) -> dict[str, Any]:
"""获取统计信息"""
cache_hit_rate = 0.0
total_requests = self._stats["cache_hits"] + self._stats["cache_misses"]
@@ -551,7 +551,7 @@ class CacheAffinityManager:
},
}
async def list_affinities(self) -> List[Dict[str, Any]]:
async def list_affinities(self) -> list[dict[str, Any]]:
"""获取所有缓存亲和性列表
返回的每条记录包含:
@@ -560,7 +560,7 @@ class CacheAffinityManager:
- api_format, model_name: API 格式和模型名称
- created_at, expire_at, request_count: 缓存元数据
"""
results: List[Dict[str, Any]] = []
results: list[dict[str, Any]] = []
try:
pattern = "cache_affinity:*"
@@ -605,7 +605,7 @@ class CacheAffinityManager:
break
else:
snapshot = await self._snapshot_memory_items()
expired_keys: List[str] = []
expired_keys: list[str] = []
current_time = time.time()
for cache_key, affinity in snapshot.items():
@@ -644,7 +644,7 @@ class CacheAffinityManager:
# 全局单例
_affinity_manager: Optional[CacheAffinityManager] = None
_affinity_manager: CacheAffinityManager | None = None
async def get_affinity_manager(redis_client=None) -> CacheAffinityManager:

View File

@@ -28,14 +28,13 @@
- 失效缓存亲和性,避免重复选择故障资源
"""
from __future__ import annotations
import hashlib
import random
import re
import time
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set, Tuple, Union
from typing import TYPE_CHECKING, Any
from sqlalchemy.orm import Session, selectinload
@@ -65,7 +64,6 @@ from src.services.rate_limit.adaptive_reservation import (
get_adaptive_reservation_manager,
)
from src.services.rate_limit.concurrency_manager import get_concurrency_manager
from src.services.system.config import SystemConfigService
@dataclass
@@ -77,8 +75,8 @@ class ProviderCandidate:
key: ProviderAPIKey
is_cached: bool = False
is_skipped: bool = False # 是否被跳过
skip_reason: Optional[str] = None # 跳过原因
mapping_matched_model: Optional[str] = None # 通过映射匹配到的模型名(用于实际请求)
skip_reason: str | None = None # 跳过原因
mapping_matched_model: str | None = None # 通过映射匹配到的模型名(用于实际请求)
needs_conversion: bool = False # 是否需要格式转换
provider_api_format: str = "" # Provider 端点实际格式(用于健康度/熔断 bucket
@@ -86,7 +84,7 @@ class ProviderCandidate:
@dataclass
class ConcurrencySnapshot:
key_current: int
key_limit: Optional[int]
key_limit: int | None
is_cached_user: bool = False
# 动态预留信息
reservation_ratio: float = 0.0
@@ -134,8 +132,8 @@ class CacheAwareScheduler:
def __init__(
self,
redis_client=None,
priority_mode: Optional[str] = None,
scheduling_mode: Optional[str] = None,
priority_mode: str | None = None,
scheduling_mode: str | None = None,
):
"""
初始化调度器
@@ -160,7 +158,7 @@ class CacheAwareScheduler:
)
# 初始化子组件(将在第一次使用时异步初始化)
self._affinity_manager: Optional[CacheAffinityManager] = None
self._affinity_manager: CacheAffinityManager | None = None
self._concurrency_manager = None
# 动态预留管理器(同步初始化)
self._reservation_manager: AdaptiveReservationManager = get_adaptive_reservation_manager()
@@ -194,13 +192,13 @@ class CacheAwareScheduler:
self,
db: Session,
affinity_key: str,
api_format: Union[str, APIFormat],
api_format: str | APIFormat,
model_name: str,
excluded_endpoints: Optional[List[str]] = None,
excluded_keys: Optional[List[str]] = None,
excluded_endpoints: list[str] | None = None,
excluded_keys: list[str] | None = None,
provider_batch_size: int = 20,
max_candidates_per_batch: Optional[int] = None,
) -> Tuple[Provider, ProviderEndpoint, ProviderAPIKey]:
max_candidates_per_batch: int | None = None,
) -> tuple[Provider, ProviderEndpoint, ProviderAPIKey]:
"""
缓存感知选择 - 核心方法
@@ -318,7 +316,7 @@ class CacheAwareScheduler:
raise ProviderNotAvailableException("服务暂时繁忙,请稍后重试")
def _get_effective_rpm_limit(self, key: ProviderAPIKey) -> Optional[int]:
def _get_effective_rpm_limit(self, key: ProviderAPIKey) -> int | None:
"""
获取有效的 RPM 限制
@@ -348,7 +346,7 @@ class CacheAwareScheduler:
self,
key: ProviderAPIKey,
is_cached_user: bool = False,
) -> Tuple[bool, ConcurrencySnapshot]:
) -> tuple[bool, ConcurrencySnapshot]:
"""
检查 RPM 限制是否可用(使用动态预留机制)
@@ -448,7 +446,7 @@ class CacheAwareScheduler:
)
can_use = False
key_limit_for_snapshot: Optional[int]
key_limit_for_snapshot: int | None
if is_cached_user:
key_limit_for_snapshot = effective_key_limit
elif effective_key_limit is not None:
@@ -471,8 +469,8 @@ class CacheAwareScheduler:
def _get_effective_restrictions(
self,
user_api_key: Optional[ApiKey],
) -> Dict[str, Any]:
user_api_key: ApiKey | None,
) -> dict[str, Any]:
"""
获取有效的访问限制(合并 ApiKey 和 User 的限制)
@@ -549,16 +547,16 @@ class CacheAwareScheduler:
async def list_all_candidates(
self,
db: Session,
api_format: Union[str, APIFormat],
api_format: str | APIFormat,
model_name: str,
affinity_key: Optional[str] = None,
user_api_key: Optional[ApiKey] = None,
affinity_key: str | None = None,
user_api_key: ApiKey | None = None,
provider_offset: int = 0,
provider_limit: Optional[int] = None,
max_candidates: Optional[int] = None,
provider_limit: int | None = None,
max_candidates: int | None = None,
is_stream: bool = False,
capability_requirements: Optional[Dict[str, bool]] = None,
) -> Tuple[List[ProviderCandidate], str]:
capability_requirements: dict[str, bool] | None = None,
) -> tuple[list[ProviderCandidate], str]:
"""
预先获取所有可用的 Provider/Endpoint/Key 组合
@@ -599,7 +597,7 @@ class CacheAwareScheduler:
global_model_id: str = str(global_model.id)
# 提取模型映射(用于 Provider Key 的 allowed_models 匹配)
model_mappings: List[str] = (global_model.config or {}).get("model_mappings", [])
model_mappings: list[str] = (global_model.config or {}).get("model_mappings", [])
if model_mappings:
logger.debug(
f"[Scheduler] GlobalModel={global_model.name} 配置了映射规则: {model_mappings}"
@@ -712,8 +710,8 @@ class CacheAwareScheduler:
self,
db: Session,
provider_offset: int = 0,
provider_limit: Optional[int] = None,
) -> List[Provider]:
provider_limit: int | None = None,
) -> list[Provider]:
"""
查询活跃的 Providers带预加载
@@ -751,10 +749,10 @@ class CacheAwareScheduler:
db: Session,
provider: Provider,
model_name: str,
api_format: Optional[str] = None,
api_format: str | None = None,
is_stream: bool = False,
capability_requirements: Optional[Dict[str, bool]] = None,
) -> Tuple[bool, Optional[str], Optional[List[str]], Optional[set[str]]]:
capability_requirements: dict[str, bool] | None = None,
) -> tuple[bool, str | None, list[str] | None, set[str] | None]:
"""
检查 Provider 是否支持指定模型(可选检查流式支持和能力需求)
@@ -807,12 +805,12 @@ class CacheAwareScheduler:
self,
db: Session,
provider: Provider,
global_model: "GlobalModel",
global_model: GlobalModel,
model_name: str,
api_format: Optional[str] = None,
api_format: str | None = None,
is_stream: bool = False,
capability_requirements: Optional[Dict[str, bool]] = None,
) -> Tuple[bool, Optional[str], Optional[List[str]], Optional[set[str]]]:
capability_requirements: dict[str, bool] | None = None,
) -> tuple[bool, str | None, list[str] | None, set[str] | None]:
"""
检查 Provider 是否支持指定的 GlobalModel
@@ -841,7 +839,7 @@ class CacheAwareScheduler:
pass
# 获取模型支持的能力列表
model_supported_capabilities: List[str] = list(global_model.supported_capabilities or [])
model_supported_capabilities: list[str] = list(global_model.supported_capabilities or [])
# 查询该 Provider 是否有实现这个 GlobalModel
for model in provider.models:
@@ -892,12 +890,12 @@ class CacheAwareScheduler:
def _check_key_availability(
self,
key: ProviderAPIKey,
api_format: Optional[str],
api_format: str | None,
model_name: str,
capability_requirements: Optional[Dict[str, bool]] = None,
model_mappings: Optional[List[str]] = None,
candidate_models: Optional[set[str]] = None,
) -> Tuple[bool, Optional[str], Optional[str]]:
capability_requirements: dict[str, bool] | None = None,
model_mappings: list[str] | None = None,
candidate_models: set[str] | None = None,
) -> tuple[bool, str | None, str | None]:
"""
检查 API Key 的可用性
@@ -971,7 +969,7 @@ class CacheAwareScheduler:
# 因为 check_capability_match 会检查 Key 的 EXCLUSIVE 能力是否被浪费
from src.core.key_capabilities import check_capability_match
key_caps: Dict[str, bool] = dict(key.capabilities or {})
key_caps: dict[str, bool] = dict(key.capabilities or {})
is_match, skip_reason = check_capability_match(key_caps, capability_requirements)
if not is_match:
return False, skip_reason, None
@@ -981,16 +979,16 @@ class CacheAwareScheduler:
async def _build_candidates(
self,
db: Session,
providers: List[Provider],
providers: list[Provider],
client_format: APIFormat,
model_name: str,
affinity_key: Optional[str],
model_mappings: Optional[List[str]] = None,
max_candidates: Optional[int] = None,
affinity_key: str | None,
model_mappings: list[str] | None = None,
max_candidates: int | None = None,
is_stream: bool = False,
capability_requirements: Optional[Dict[str, bool]] = None,
capability_requirements: dict[str, bool] | None = None,
global_conversion_enabled: bool = False,
) -> List[ProviderCandidate]:
) -> list[ProviderCandidate]:
"""
构建候选列表
@@ -1013,18 +1011,18 @@ class CacheAwareScheduler:
"""
from src.core.api_format.conversion.compatibility import is_format_compatible
candidates: List[ProviderCandidate] = []
candidates: list[ProviderCandidate] = []
client_format_str = client_format.value
for provider in providers:
# 按端点格式分别判断兼容性与模型/Key 可用性:
# - 同格式端点优先needs_conversion=False
# - 跨格式端点次之needs_conversion=True
model_support_cache: Dict[
str, Tuple[bool, Optional[str], Optional[List[str]], Optional[Set[str]]]
model_support_cache: dict[
str, tuple[bool, str | None, list[str] | None, set[str] | None]
] = {}
exact_candidates: List[ProviderCandidate] = []
convertible_candidates: List[ProviderCandidate] = []
exact_candidates: list[ProviderCandidate] = []
convertible_candidates: list[ProviderCandidate] = []
for endpoint in provider.endpoints:
if not endpoint.is_active:
@@ -1130,11 +1128,11 @@ class CacheAwareScheduler:
async def _apply_cache_affinity(
self,
candidates: List[ProviderCandidate],
candidates: list[ProviderCandidate],
affinity_key: str,
api_format: APIFormat,
global_model_id: str,
) -> List[ProviderCandidate]:
) -> list[ProviderCandidate]:
"""
应用缓存亲和性排序
@@ -1177,7 +1175,7 @@ class CacheAwareScheduler:
return True # 需要降级
# 按是否匹配缓存亲和性分类候选,同时记录是否降级
matched_candidate: Optional[ProviderCandidate] = None
matched_candidate: ProviderCandidate | None = None
matched = False
for candidate in candidates:
@@ -1231,8 +1229,8 @@ class CacheAwareScheduler:
matched_should_demote = should_demote(matched_candidate)
# 分组:非降级类 和 降级类
keep_priority_candidates: List[ProviderCandidate] = []
demote_candidates: List[ProviderCandidate] = []
keep_priority_candidates: list[ProviderCandidate] = []
demote_candidates: list[ProviderCandidate] = []
for c in candidates:
if c is matched_candidate:
@@ -1258,7 +1256,7 @@ class CacheAwareScheduler:
logger.warning(f"检查缓存亲和性失败: {e},继续使用默认排序")
return candidates
def _normalize_priority_mode(self, mode: Optional[str]) -> str:
def _normalize_priority_mode(self, mode: str | None) -> str:
normalized = (mode or "").strip().lower()
if normalized not in self.ALLOWED_PRIORITY_MODES:
if normalized:
@@ -1266,7 +1264,7 @@ class CacheAwareScheduler:
return self.PRIORITY_MODE_PROVIDER
return normalized
def set_priority_mode(self, mode: Optional[str]) -> None:
def set_priority_mode(self, mode: str | None) -> None:
"""运行时更新候选排序策略"""
normalized = self._normalize_priority_mode(mode)
if normalized == self.priority_mode:
@@ -1274,7 +1272,7 @@ class CacheAwareScheduler:
self.priority_mode = normalized
logger.debug(f"[CacheAwareScheduler] 切换优先级模式为: {self.priority_mode}")
def _normalize_scheduling_mode(self, mode: Optional[str]) -> str:
def _normalize_scheduling_mode(self, mode: str | None) -> str:
normalized = (mode or "").strip().lower()
if normalized not in self.ALLOWED_SCHEDULING_MODES:
if normalized:
@@ -1284,7 +1282,7 @@ class CacheAwareScheduler:
return self.SCHEDULING_MODE_CACHE_AFFINITY
return normalized
def set_scheduling_mode(self, mode: Optional[str]) -> None:
def set_scheduling_mode(self, mode: str | None) -> None:
"""运行时更新调度模式"""
normalized = self._normalize_scheduling_mode(mode)
if normalized == self.scheduling_mode:
@@ -1294,10 +1292,10 @@ class CacheAwareScheduler:
def _apply_priority_mode_sort(
self,
candidates: List[ProviderCandidate],
affinity_key: Optional[str] = None,
api_format: Optional[str] = None,
) -> List[ProviderCandidate]:
candidates: list[ProviderCandidate],
affinity_key: str | None = None,
api_format: str | None = None,
) -> list[ProviderCandidate]:
"""
根据优先级模式对候选列表排序(数字越小越优先)
@@ -1328,8 +1326,8 @@ class CacheAwareScheduler:
# 全局未开启:按是否需要降级分组
# - 不需要降级exact 候选 或 provider.keep_priority_on_conversion=True 的 convertible 候选
# - 需要降级convertible 且 provider.keep_priority_on_conversion=False
keep_priority_candidates: List[ProviderCandidate] = []
demote_candidates: List[ProviderCandidate] = []
keep_priority_candidates: list[ProviderCandidate] = []
demote_candidates: list[ProviderCandidate] = []
for c in candidates:
if not c.needs_conversion:
@@ -1357,10 +1355,10 @@ class CacheAwareScheduler:
def _sort_by_global_priority_with_hash(
self,
candidates: List[ProviderCandidate],
affinity_key: Optional[str] = None,
api_format: Optional[str] = None,
) -> List[ProviderCandidate]:
candidates: list[ProviderCandidate],
affinity_key: str | None = None,
api_format: str | None = None,
) -> list[ProviderCandidate]:
"""
按 global_priority_by_format 分组排序,同优先级内通过哈希分散实现负载均衡
@@ -1382,7 +1380,7 @@ class CacheAwareScheduler:
return 999999 # NULL 排在后面
# 按优先级分组
priority_groups: Dict[int, List[ProviderCandidate]] = defaultdict(list)
priority_groups: dict[int, list[ProviderCandidate]] = defaultdict(list)
for candidate in candidates:
priority = get_priority(candidate)
priority_groups[priority].append(candidate)
@@ -1417,8 +1415,8 @@ class CacheAwareScheduler:
return result
def _apply_load_balance(
self, candidates: List[ProviderCandidate], api_format: Optional[str] = None
) -> List[ProviderCandidate]:
self, candidates: list[ProviderCandidate], api_format: str | None = None
) -> list[ProviderCandidate]:
"""
负载均衡模式:同优先级内随机轮换
@@ -1432,7 +1430,7 @@ class CacheAwareScheduler:
from collections import defaultdict
priority_groups: Dict[tuple, List[ProviderCandidate]] = defaultdict(list)
priority_groups: dict[tuple, list[ProviderCandidate]] = defaultdict(list)
# 根据优先级模式选择分组方式
if self.priority_mode == self.PRIORITY_MODE_GLOBAL_KEY:
@@ -1453,7 +1451,7 @@ class CacheAwareScheduler:
)
priority_groups[key].append(candidate)
result: List[ProviderCandidate] = []
result: list[ProviderCandidate] = []
for priority in sorted(priority_groups.keys()):
group = priority_groups[priority]
if len(group) > 1:
@@ -1468,10 +1466,10 @@ class CacheAwareScheduler:
def _shuffle_keys_by_internal_priority(
self,
keys: List[ProviderAPIKey],
affinity_key: Optional[str] = None,
keys: list[ProviderAPIKey],
affinity_key: str | None = None,
use_random: bool = False,
) -> List[ProviderAPIKey]:
) -> list[ProviderAPIKey]:
"""
对 API Key 按 internal_priority 分组,同优先级内部基于 affinity_key 进行确定性打乱
@@ -1495,7 +1493,7 @@ class CacheAwareScheduler:
# 按 internal_priority 分组
from collections import defaultdict
priority_groups: Dict[int, List[ProviderAPIKey]] = defaultdict(list)
priority_groups: dict[int, list[ProviderAPIKey]] = defaultdict(list)
for key in keys:
priority = key.internal_priority if key.internal_priority is not None else 999999
@@ -1538,9 +1536,9 @@ class CacheAwareScheduler:
affinity_key: str,
api_format: str,
global_model_id: str,
endpoint_id: Optional[str] = None,
key_id: Optional[str] = None,
provider_id: Optional[str] = None,
endpoint_id: str | None = None,
key_id: str | None = None,
provider_id: str | None = None,
):
"""
失效指定亲和性标识符对特定API格式和模型的缓存亲和性
@@ -1571,7 +1569,7 @@ class CacheAwareScheduler:
key_id: str,
api_format: str,
global_model_id: str,
ttl: Optional[int] = None,
ttl: int | None = None,
):
"""
记录缓存亲和性(供编排器调用)
@@ -1641,13 +1639,13 @@ class CacheAwareScheduler:
# 全局单例
_scheduler: Optional[CacheAwareScheduler] = None
_scheduler: CacheAwareScheduler | None = None
async def get_cache_aware_scheduler(
redis_client=None,
priority_mode: Optional[str] = None,
scheduling_mode: Optional[str] = None,
priority_mode: str | None = None,
scheduling_mode: str | None = None,
) -> CacheAwareScheduler:
"""
获取全局CacheAwareScheduler实例

View File

@@ -15,7 +15,7 @@ import json
import time
from abc import ABC, abstractmethod
from collections import OrderedDict
from typing import Any, Dict, Optional
from typing import Any
import redis.asyncio as aioredis
from src.core.logger import logger
@@ -28,7 +28,7 @@ class BaseCacheBackend(ABC):
"""缓存后端抽象基类"""
@abstractmethod
async def get(self, key: str) -> Optional[Any]:
async def get(self, key: str) -> Any | None:
"""获取缓存值"""
pass
@@ -43,7 +43,7 @@ class BaseCacheBackend(ABC):
pass
@abstractmethod
async def clear(self, pattern: Optional[str] = None) -> None:
async def clear(self, pattern: str | None = None) -> None:
"""清空缓存(支持模式匹配)"""
pass
@@ -65,12 +65,12 @@ class LocalCache(BaseCacheBackend):
default_ttl: 默认过期时间(秒)
"""
self._cache: OrderedDict = OrderedDict()
self._expiry: Dict[str, float] = {}
self._expiry: dict[str, float] = {}
self._max_size = max_size
self._default_ttl = default_ttl
self._lock = asyncio.Lock()
async def get(self, key: str) -> Optional[Any]:
async def get(self, key: str) -> Any | None:
"""获取缓存值(线程安全)"""
async with self._lock:
if key not in self._cache:
@@ -115,7 +115,7 @@ class LocalCache(BaseCacheBackend):
if key in self._expiry:
del self._expiry[key]
async def clear(self, pattern: Optional[str] = None) -> None:
async def clear(self, pattern: str | None = None) -> None:
"""清空缓存(线程安全)"""
async with self._lock:
if pattern is None:
@@ -145,7 +145,7 @@ class LocalCache(BaseCacheBackend):
return True
def get_stats(self) -> Dict[str, Any]:
def get_stats(self) -> dict[str, Any]:
"""获取缓存统计信息"""
return {
"backend": "local",
@@ -177,7 +177,7 @@ class RedisCache(BaseCacheBackend):
"""构造完整的 Redis 键"""
return f"{self._key_prefix}:{key}"
async def get(self, key: str) -> Optional[Any]:
async def get(self, key: str) -> Any | None:
"""获取缓存值"""
try:
redis_key = self._make_key(key)
@@ -223,7 +223,7 @@ class RedisCache(BaseCacheBackend):
except Exception as e:
logger.error(f"[RedisCache] 删除缓存失败: {key}, 错误: {e}")
async def clear(self, pattern: Optional[str] = None) -> None:
async def clear(self, pattern: str | None = None) -> None:
"""清空缓存"""
try:
if pattern is None:
@@ -264,7 +264,7 @@ class RedisCache(BaseCacheBackend):
except Exception as e:
logger.error(f"[RedisCache] 发布缓存失效失败: {channel}, {key}, 错误: {e}")
def get_stats(self) -> Dict[str, Any]:
def get_stats(self) -> dict[str, Any]:
"""获取缓存统计信息"""
return {
"backend": "redis",
@@ -274,7 +274,7 @@ class RedisCache(BaseCacheBackend):
# 缓存后端工厂
_cache_backends: Dict[str, BaseCacheBackend] = {}
_cache_backends: dict[str, BaseCacheBackend] = {}
async def get_cache_backend(

View File

@@ -4,7 +4,6 @@
统一管理各种缓存的失效逻辑
"""
from typing import Optional
from src.core.logger import logger
@@ -21,7 +20,7 @@ class CacheInvalidationService:
self._model_mappers.append(model_mapper)
async def on_global_model_changed(
self, model_name: str, global_model_id: Optional[str] = None
self, model_name: str, global_model_id: str | None = None
) -> None:
"""
GlobalModel 变更时的缓存失效
@@ -96,7 +95,7 @@ class CacheInvalidationService:
# 全局单例
_cache_invalidation_service: Optional[CacheInvalidationService] = None
_cache_invalidation_service: CacheInvalidationService | None = None
def get_cache_invalidation_service() -> CacheInvalidationService:

View File

@@ -19,7 +19,6 @@ Model 映射缓存服务 - 减少模型查询
"""
import time
from typing import List, Optional
from sqlalchemy.orm import Session
@@ -45,7 +44,7 @@ class ModelCacheService:
CACHE_TTL = CacheTTL.MODEL
@staticmethod
async def get_model_by_id(db: Session, model_id: str) -> Optional[Model]:
async def get_model_by_id(db: Session, model_id: str) -> Model | None:
"""
获取 Model带缓存
@@ -76,7 +75,7 @@ class ModelCacheService:
return model
@staticmethod
async def get_global_model_by_id(db: Session, global_model_id: str) -> Optional[GlobalModel]:
async def get_global_model_by_id(db: Session, global_model_id: str) -> GlobalModel | None:
"""
获取 GlobalModel带缓存
@@ -111,7 +110,7 @@ class ModelCacheService:
@staticmethod
async def get_model_by_provider_and_global_model(
db: Session, provider_id: str, global_model_id: str
) -> Optional[Model]:
) -> Model | None:
"""
通过 Provider ID 和 GlobalModel ID 获取 Model带缓存
@@ -160,7 +159,7 @@ class ModelCacheService:
return model
@staticmethod
async def get_global_model_by_name(db: Session, name: str) -> Optional[GlobalModel]:
async def get_global_model_by_name(db: Session, name: str) -> GlobalModel | None:
"""
通过名称获取 GlobalModel带缓存
@@ -195,10 +194,10 @@ class ModelCacheService:
@staticmethod
async def invalidate_model_cache(
model_id: str,
provider_id: Optional[str] = None,
global_model_id: Optional[str] = None,
provider_model_name: Optional[str] = None,
provider_model_mappings: Optional[list] = None,
provider_id: str | None = None,
global_model_id: str | None = None,
provider_model_name: str | None = None,
provider_model_mappings: list | None = None,
) -> None:
"""清除 Model 缓存
@@ -240,7 +239,7 @@ class ModelCacheService:
logger.debug(f"Model resolve 缓存已清除: {resolve_keys_to_clear}")
@staticmethod
async def invalidate_global_model_cache(global_model_id: str, name: Optional[str] = None) -> None:
async def invalidate_global_model_cache(global_model_id: str, name: str | None = None) -> None:
"""清除 GlobalModel 缓存"""
await CacheService.delete(f"global_model:id:{global_model_id}")
if name:
@@ -270,7 +269,7 @@ class ModelCacheService:
@staticmethod
async def resolve_global_model_by_name_or_mapping(
db: Session, model_name: str
) -> Optional[GlobalModel]:
) -> GlobalModel | None:
"""
通过名称解析 GlobalModel带缓存
@@ -355,7 +354,7 @@ class ModelCacheService:
)
# 收集匹配的 GlobalModel只通过 provider_model_name 匹配)
matched_global_models: List[GlobalModel] = []
matched_global_models: list[GlobalModel] = []
seen_global_model_ids: set[str] = set()
for model, gm in models_with_global:
if gm.id not in seen_global_model_ids:
@@ -405,7 +404,7 @@ class ModelCacheService:
.all()
)
mapping_matched_global_models: List[GlobalModel] = []
mapping_matched_global_models: list[GlobalModel] = []
mapping_seen_ids: set[str] = set()
for model, gm in models_with_mappings:
raw_mappings = model.provider_model_mappings
@@ -469,7 +468,7 @@ class ModelCacheService:
.all()
)
mapping_matches: List[GlobalModel] = []
mapping_matches: list[GlobalModel] = []
for gm in mapping_rows:
config = gm.config or {}
mappings = config.get("model_mappings")

View File

@@ -5,7 +5,6 @@ Provider 缓存服务 - 减少 Provider 和 ProviderAPIKey 查询
这些数据在 UsageService.record_usage() 中被频繁查询但变化不频繁。
"""
from typing import Optional, Tuple
from sqlalchemy.orm import Session
@@ -27,8 +26,8 @@ class ProviderCacheService:
@staticmethod
def compute_rate_multiplier(
rate_multipliers: Optional[dict],
api_format: Optional[str] = None,
rate_multipliers: dict | None,
api_format: str | None = None,
) -> float:
"""
计算 rate_multiplier 的纯函数(无数据库/缓存依赖)
@@ -50,8 +49,8 @@ class ProviderCacheService:
@staticmethod
async def get_provider_api_key_rate_multiplier(
db: Session, provider_api_key_id: str, api_format: Optional[str] = None
) -> Optional[float]:
db: Session, provider_api_key_id: str, api_format: str | None = None
) -> float | None:
"""
获取 ProviderAPIKey 的 rate_multiplier带缓存
@@ -106,7 +105,7 @@ class ProviderCacheService:
@staticmethod
async def get_provider_billing_type(
db: Session, provider_id: str
) -> Optional[ProviderBillingType]:
) -> ProviderBillingType | None:
"""
获取 Provider 的 billing_type带缓存
@@ -154,10 +153,10 @@ class ProviderCacheService:
@staticmethod
async def get_rate_multiplier_and_free_tier(
db: Session,
provider_api_key_id: Optional[str],
provider_id: Optional[str],
api_format: Optional[str] = None,
) -> Tuple[float, bool]:
provider_api_key_id: str | None,
provider_id: str | None,
api_format: str | None = None,
) -> tuple[float, bool]:
"""
获取费率倍数和是否免费套餐(带缓存)

View File

@@ -11,7 +11,8 @@
import asyncio
import json
from typing import Callable, Dict, Optional
from collections.abc import Callable
import redis.asyncio as aioredis
from src.core.logger import logger
@@ -40,9 +41,9 @@ class CacheSyncService:
redis_client: Redis 客户端实例
"""
self._redis = redis_client
self._pubsub: Optional[aioredis.client.PubSub] = None
self._listener_task: Optional[asyncio.Task] = None
self._handlers: Dict[str, Callable] = {}
self._pubsub: aioredis.client.PubSub | None = None
self._listener_task: asyncio.Task | None = None
self._handlers: dict[str, Callable] = {}
self._running = False
async def start(self):
@@ -160,10 +161,10 @@ class CacheSyncService:
# 全局单例
_cache_sync_service: Optional[CacheSyncService] = None
_cache_sync_service: CacheSyncService | None = None
async def get_cache_sync_service(redis_client: aioredis.Redis = None) -> Optional[CacheSyncService]:
async def get_cache_sync_service(redis_client: aioredis.Redis = None) -> CacheSyncService | None:
"""
获取缓存同步服务实例

View File

@@ -19,7 +19,6 @@
await UserCacheService.invalidate_user_cache(user_id, email)
"""
from typing import Optional
from sqlalchemy.orm import Session
@@ -40,7 +39,7 @@ class UserCacheService:
CACHE_TTL = CacheTTL.USER
@staticmethod
async def get_user_by_id(db: Session, user_id: str) -> Optional[User]:
async def get_user_by_id(db: Session, user_id: str) -> User | None:
"""
获取用户(带缓存)
@@ -72,7 +71,7 @@ class UserCacheService:
return user
@staticmethod
async def get_user_by_email(db: Session, email: str) -> Optional[User]:
async def get_user_by_email(db: Session, email: str) -> User | None:
"""
通过邮箱获取用户(带缓存)
@@ -103,7 +102,7 @@ class UserCacheService:
return user
@staticmethod
async def invalidate_user_cache(user_id: str, email: Optional[str] = None):
async def invalidate_user_cache(user_id: str, email: str | None = None):
"""
清除用户缓存