mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-23 00:53:33 +00:00
feat: 添加上游不稳定错误检测与账户临时不可用机制
## 背景
当上游 API(如 Anthropic、AWS Bedrock 等)出现临时故障时,服务会持续向故障
账户发送请求,导致用户体验下降。需要自动检测上游不稳定状态并临时排除故障账户。
## 改动内容
### 新增 unstableUpstreamHelper.js
- 检测多种上游不稳定错误模式
- 支持环境变量扩展检测规则
### 修改 unifiedClaudeScheduler.js
- 新增 markAccountTemporarilyUnavailable() 方法:标记账户临时不可用
- 新增 isAccountTemporarilyUnavailable() 方法:检查账户是否临时不可用
- 专属账户检查:claude-official、claude-console、bedrock 临时不可用时自动回退到池
- 池账户选择:跳过临时不可用的账户
### 修改 claudeRelayService.js
- _handleServerError() 方法增加临时不可用标记逻辑
- 5xx 错误时自动标记账户临时不可用(5分钟 TTL)
## 检测的状态码
| 分类 | 状态码 | 说明 |
|------|--------|------|
| 服务器错误 | 500-599 | 内部错误、服务不可用等 |
| 超时类 | 408 | 请求超时 |
| 连接类 | 499 | 客户端关闭请求 (Nginx) |
| 网关类 | 502, 503, 504 | 网关错误、服务不可用、网关超时 |
| CDN类 | 522 | Cloudflare 连接超时 |
| 语义类 | error.type = "server_error" | API 级别服务器错误 |
## 环境变量配置
- UNSTABLE_ERROR_TYPES: 额外的错误类型(逗号分隔)
- UNSTABLE_ERROR_KEYWORDS: 错误消息关键词(逗号分隔)
## Redis 键
- temp_unavailable:{accountType}:{accountId} - TTL 300秒
This commit is contained in:
@@ -1948,7 +1948,13 @@ class ClaudeRelayService {
|
||||
}
|
||||
|
||||
// 🛠️ 统一的错误处理方法
|
||||
async _handleServerError(accountId, statusCode, _sessionHash = null, context = '') {
|
||||
async _handleServerError(
|
||||
accountId,
|
||||
statusCode,
|
||||
sessionHash = null,
|
||||
context = '',
|
||||
accountType = 'claude-official'
|
||||
) {
|
||||
try {
|
||||
await claudeAccountService.recordServerError(accountId, statusCode)
|
||||
const errorCount = await claudeAccountService.getServerErrorCount(accountId)
|
||||
@@ -1962,6 +1968,18 @@ class ClaudeRelayService {
|
||||
`⏱️ ${prefix}${isTimeout ? 'Timeout' : 'Server'} error for account ${accountId}, error count: ${errorCount}/${threshold}`
|
||||
)
|
||||
|
||||
// 标记账户为临时不可用(5分钟)
|
||||
try {
|
||||
await unifiedClaudeScheduler.markAccountTemporarilyUnavailable(
|
||||
accountId,
|
||||
accountType,
|
||||
sessionHash,
|
||||
300
|
||||
)
|
||||
} catch (markError) {
|
||||
logger.error(`❌ Failed to mark account temporarily unavailable: ${accountId}`, markError)
|
||||
}
|
||||
|
||||
if (errorCount > threshold) {
|
||||
const errorTypeLabel = isTimeout ? 'timeout' : '5xx'
|
||||
// ⚠️ 只记录5xx/504告警,不再自动停止调度,避免上游抖动导致误停
|
||||
|
||||
Reference in New Issue
Block a user