fix: Hub 连接清理顺序修复、OAuth 类型常量提取、disassociate 逻辑优化

- Hub proxy/worker 连接关闭时先 unregister 再延迟 abort writer,确保缓冲消息排空
- 提取 OAUTH_AUTH_TYPES 常量,替代各处硬编码的 OAuth 类型列表
- auto-disassociate 跳过 OAuth Key,避免其动态 allowed_models 干扰判定
- 删除 Key 时传入 skip_disassociate=True,跳过不必要的解关联检查
- ModelMapper 缓存命中时将 ORM 实例脱离 Session,修复 DetachedInstanceError
This commit is contained in:
fawney19
2026-03-08 23:03:56 +08:00
parent f5f7a23bb0
commit 91b6e0a382
9 changed files with 40 additions and 12 deletions

View File

@@ -498,14 +498,20 @@ class GlobalModelService:
logger.warning(f"Provider {provider_id} not found for auto-disassociation")
return results
# 1. 先快速检查是否存在允许所有模型的活跃 Key。
# 1. 先快速检查是否存在"允许所有模型"的活跃 Key。
# 这种情况下无需解除任何关联,避免继续扫描整张 key 表。
# 注意:跳过 OAuth KeyOAuth Key 的 allowed_models 由上游动态获取,数量庞大,
# 不应参与 disassociate 判定。
from src.services.provider_keys.auth_type import OAUTH_AUTH_TYPES
non_oauth_filter = ProviderAPIKey.auth_type.notin_(OAUTH_AUTH_TYPES)
has_unlimited_key = (
db.query(ProviderAPIKey.id)
.filter(
ProviderAPIKey.provider_id == provider_id,
ProviderAPIKey.is_active == True,
ProviderAPIKey.allowed_models.is_(None),
non_oauth_filter,
)
.limit(1)
.first()
@@ -520,6 +526,7 @@ class GlobalModelService:
.filter(
ProviderAPIKey.provider_id == provider_id,
ProviderAPIKey.is_active == True,
non_oauth_filter,
)
.all()
)

View File

@@ -110,6 +110,13 @@ class ModelMapperMiddleware:
)
if model:
# 将 ORM Model 转为无 Session 绑定的实例,避免跨请求缓存导致 DetachedInstanceError
from sqlalchemy.orm.session import object_session
if object_session(model) is not None:
model_dict = ModelCacheService._model_to_dict(model)
model = ModelCacheService._dict_to_model(model_dict)
# 创建映射对象
mapping = type(
"obj",

View File

@@ -2,6 +2,10 @@
Provider Key 认证类型相关规则。
"""
# 数据库中所有属于 OAuth 的 auth_type 值(含历史别名)。
# 新增 OAuth 类型时只需在此追加SQL 过滤和 Python 判断均引用此常量。
OAUTH_AUTH_TYPES: tuple[str, ...] = ("oauth", "kiro")
def normalize_auth_type(raw: str) -> str:
"""将数据库中的 auth_type 归一化为逻辑类型。

View File

@@ -134,9 +134,6 @@ async def run_delete_key_side_effects(
deleted_key_allowed_models: list[str] | None,
) -> None:
"""执行删除 Key 后的副作用。"""
# 触发缓存失效和自动解除关联检查
# 注意:删除后是否需要解除关联,应基于“删除后的活跃 Key 集合”判断。
# 不能仅凭被删除 Key 的 allowed_models 是否为 null 来跳过 disassociate。
_ = deleted_key_allowed_models
if provider_id:
from src.services.model.global_model import on_key_allowed_models_changed
@@ -144,6 +141,7 @@ async def run_delete_key_side_effects(
await on_key_allowed_models_changed(
db=db,
provider_id=provider_id,
skip_disassociate=True,
)
else:
# 无 provider_id 时仅清除缓存