feat(cache): improve model cache invalidation for alias resolution

- Add provider_model_name and provider_model_aliases to invalidate_model_cache()
- Clear resolve cache keys for both model name and aliases when invalidating
- Also clear resolve cache in invalidate_global_model_cache() for GlobalModel names
- Handle SQLite gracefully by catching OperationalError and ProgrammingError
- Optimize fallback query to pre-filter by provider_model_name when JSONB fails
This commit is contained in:
fawney19
2025-12-15 18:27:31 +08:00
parent c6fcc7982d
commit d9bd0790fe

View File

@@ -6,6 +6,7 @@ import json
import time import time
from typing import Optional from typing import Optional
from sqlalchemy.exc import OperationalError, ProgrammingError
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from src.config.constants import CacheTTL from src.config.constants import CacheTTL
@@ -170,7 +171,11 @@ class ModelCacheService:
@staticmethod @staticmethod
async def invalidate_model_cache( async def invalidate_model_cache(
model_id: str, provider_id: Optional[str] = None, global_model_id: Optional[str] = None model_id: str,
provider_id: Optional[str] = None,
global_model_id: Optional[str] = None,
provider_model_name: Optional[str] = None,
provider_model_aliases: Optional[list] = None,
) -> None: ) -> None:
"""清除 Model 缓存 """清除 Model 缓存
@@ -178,6 +183,8 @@ class ModelCacheService:
model_id: Model ID model_id: Model ID
provider_id: Provider ID用于清除 provider_global 缓存) provider_id: Provider ID用于清除 provider_global 缓存)
global_model_id: GlobalModel ID用于清除 provider_global 缓存) global_model_id: GlobalModel ID用于清除 provider_global 缓存)
provider_model_name: provider_model_name用于清除 resolve 缓存)
provider_model_aliases: 别名列表(用于清除 resolve 缓存)
""" """
# 清除 model:id 缓存 # 清除 model:id 缓存
await CacheService.delete(f"model:id:{model_id}") await CacheService.delete(f"model:id:{model_id}")
@@ -191,12 +198,31 @@ class ModelCacheService:
else: else:
logger.debug(f"Model 缓存已清除: {model_id}") logger.debug(f"Model 缓存已清除: {model_id}")
# 清除 resolve 缓存provider_model_name 和 aliases 可能都被用作解析 key
resolve_keys_to_clear = []
if provider_model_name:
resolve_keys_to_clear.append(provider_model_name)
if provider_model_aliases:
for alias_entry in provider_model_aliases:
if isinstance(alias_entry, dict):
alias_name = alias_entry.get("name", "").strip()
if alias_name:
resolve_keys_to_clear.append(alias_name)
for key in resolve_keys_to_clear:
await CacheService.delete(f"global_model:resolve:{key}")
if resolve_keys_to_clear:
logger.debug(f"Model resolve 缓存已清除: {resolve_keys_to_clear}")
@staticmethod @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: Optional[str] = None) -> None:
"""清除 GlobalModel 缓存""" """清除 GlobalModel 缓存"""
await CacheService.delete(f"global_model:id:{global_model_id}") await CacheService.delete(f"global_model:id:{global_model_id}")
if name: if name:
await CacheService.delete(f"global_model:name:{name}") await CacheService.delete(f"global_model:name:{name}")
# 同时清除 resolve 缓存,因为 GlobalModel.name 也是一个 resolve key
await CacheService.delete(f"global_model:resolve:{name}")
logger.debug(f"GlobalModel 缓存已清除: {global_model_id}") logger.debug(f"GlobalModel 缓存已清除: {global_model_id}")
@staticmethod @staticmethod
@@ -292,11 +318,13 @@ class ModelCacheService:
) )
.all() .all()
) )
except Exception as e: except (OperationalError, ProgrammingError) as e:
# 如果 JSONB 查询失败(如使用 SQLite回退到加载所有活跃 Model 并在 Python 层过滤 # JSONB 操作符不支持(如 SQLite回退到加载匹配 provider_model_name 的 Model
# 并在 Python 层过滤 aliases
logger.debug( logger.debug(
f"JSONB 查询失败,回退到 Python 过滤: {e}", f"JSONB 查询失败,回退到 Python 过滤: {e}",
) )
# 优化:先用 provider_model_name 缩小范围,再加载其他可能匹配的记录
models_with_global = ( models_with_global = (
db.query(Model, GlobalModel) db.query(Model, GlobalModel)
.join(Provider, Model.provider_id == Provider.id) .join(Provider, Model.provider_id == Provider.id)