mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 09:20:22 +08:00
feat(failover): 支持 Provider 级别故障转移规则,默认全部转移策略
- 新增 failover_rules 配置:支持 success_failover_patterns(成功响应匹配时转移) 和 error_stop_patterns(错误响应匹配时终止),支持按 status_code 过滤 - 修改默认转移策略:ErrorClassifier 不再返回 RAISE,所有错误默认继续转移 - TaskService 中客户端错误不再直接抛出,改为 break 继续尝试下一个候选 - 修复 proxy tunnel 连接/断连竞态:引入 per-node 锁和事件时间戳排序 - 优化 ProxyNode 状态判定:OFFLINE 统一由心跳超时判定,兼容多 worker 场景 - has_tunnel 改为纯检查方法,避免在 finally 块中误清理新注册连接 - Redis stream NOGROUP 异常自愈处理 - OAuthAccountDialog 输入框焦点样式补全
This commit is contained in:
@@ -80,6 +80,53 @@ class ProxyConfig(BaseModel):
|
||||
return self
|
||||
|
||||
|
||||
class FailoverRuleItem(BaseModel):
|
||||
"""故障转移规则条目"""
|
||||
|
||||
pattern: str = Field(..., min_length=1, max_length=500, description="正则表达式")
|
||||
description: str = Field("", max_length=200, description="规则描述")
|
||||
status_codes: list[int] | None = Field(
|
||||
default=None,
|
||||
description="HTTP 状态码列表(可选,为空时匹配所有状态码)",
|
||||
)
|
||||
|
||||
@field_validator("pattern")
|
||||
@classmethod
|
||||
def validate_pattern(cls, v: str) -> str:
|
||||
"""验证正则表达式语法"""
|
||||
import re as _re
|
||||
|
||||
try:
|
||||
_re.compile(v)
|
||||
except _re.error as e:
|
||||
raise ValueError(f"无效的正则表达式: {e}")
|
||||
return v
|
||||
|
||||
@field_validator("status_codes")
|
||||
@classmethod
|
||||
def validate_status_codes(cls, v: list[int] | None) -> list[int] | None:
|
||||
"""验证 HTTP 状态码"""
|
||||
if v is None:
|
||||
return v
|
||||
for code in v:
|
||||
if not (100 <= code <= 599):
|
||||
raise ValueError(f"无效的 HTTP 状态码: {code}")
|
||||
return v
|
||||
|
||||
|
||||
class FailoverRulesConfig(BaseModel):
|
||||
"""故障转移规则配置"""
|
||||
|
||||
success_failover_patterns: list[FailoverRuleItem] = Field(
|
||||
default_factory=list,
|
||||
description="成功响应转移规则: HTTP 200 但响应体匹配正则时触发转移",
|
||||
)
|
||||
error_stop_patterns: list[FailoverRuleItem] = Field(
|
||||
default_factory=list,
|
||||
description="错误终止规则: HTTP 非 200 且响应体匹配正则时停止转移",
|
||||
)
|
||||
|
||||
|
||||
class PoolAdvancedConfig(BaseModel):
|
||||
"""通用号池配置(适用于所有 Provider 类型)。"""
|
||||
|
||||
@@ -247,6 +294,7 @@ class CreateProviderRequest(BaseModel):
|
||||
claude_code_advanced: ClaudeCodeAdvancedConfig | None = Field(
|
||||
None, description="Claude Code 特有配置"
|
||||
)
|
||||
failover_rules: FailoverRulesConfig | None = Field(None, description="故障转移规则配置")
|
||||
config: dict[str, Any] | None = Field(None, description="其他配置")
|
||||
|
||||
@field_validator("provider_type")
|
||||
@@ -356,6 +404,7 @@ class UpdateProviderRequest(BaseModel):
|
||||
claude_code_advanced: ClaudeCodeAdvancedConfig | None = Field(
|
||||
None, description="Claude Code 特有配置"
|
||||
)
|
||||
failover_rules: FailoverRulesConfig | None = Field(None, description="故障转移规则配置")
|
||||
config: dict[str, Any] | None = None
|
||||
|
||||
# 复用相同的验证器
|
||||
|
||||
@@ -10,7 +10,12 @@ from typing import Any, Literal
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
||||
|
||||
from src.models.admin_requests import ClaudeCodeAdvancedConfig, PoolAdvancedConfig, ProxyConfig
|
||||
from src.models.admin_requests import (
|
||||
ClaudeCodeAdvancedConfig,
|
||||
FailoverRulesConfig,
|
||||
PoolAdvancedConfig,
|
||||
ProxyConfig,
|
||||
)
|
||||
|
||||
# ========== Header Rule 类型定义 ==========
|
||||
# 请求头规则支持三种操作:
|
||||
@@ -938,6 +943,7 @@ class ProviderUpdateRequest(BaseModel):
|
||||
None, description="Claude Code 高级配置"
|
||||
)
|
||||
pool_advanced: PoolAdvancedConfig | None = Field(None, description="通用号池配置")
|
||||
failover_rules: FailoverRulesConfig | None = Field(None, description="故障转移规则配置")
|
||||
|
||||
|
||||
class ProviderWithEndpointsSummary(BaseModel):
|
||||
@@ -982,6 +988,7 @@ class ProviderWithEndpointsSummary(BaseModel):
|
||||
default=None, description="Claude Code 高级配置"
|
||||
)
|
||||
pool_advanced: PoolAdvancedConfig | None = Field(default=None, description="通用号池配置")
|
||||
failover_rules: FailoverRulesConfig | None = Field(default=None, description="故障转移规则配置")
|
||||
|
||||
# Endpoint 统计
|
||||
total_endpoints: int = Field(default=0, description="总 Endpoint 数量")
|
||||
|
||||
Reference in New Issue
Block a user