mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-05-06 18:41:37 +00:00
Merge pull request #341 from sczheng189/fix-schedulable-check
Fix:修复重置状态错误以及5xx熔断状态清除
This commit is contained in:
@@ -1813,6 +1813,20 @@ class ClaudeAccountService {
|
||||
// 保存更新后的账户数据
|
||||
await redis.setClaudeAccount(accountId, updatedAccountData)
|
||||
|
||||
// 显式从 Redis 中删除这些字段(因为 HSET 不会删除现有字段)
|
||||
const fieldsToDelete = [
|
||||
'errorMessage',
|
||||
'unauthorizedAt',
|
||||
'blockedAt',
|
||||
'rateLimitedAt',
|
||||
'rateLimitStatus',
|
||||
'rateLimitEndAt',
|
||||
'tempErrorAt',
|
||||
'sessionWindowStart',
|
||||
'sessionWindowEnd'
|
||||
]
|
||||
await redis.client.hdel(`claude:account:${accountId}`, ...fieldsToDelete)
|
||||
|
||||
// 清除401错误计数
|
||||
const errorKey = `claude_account:${accountId}:401_errors`
|
||||
await redis.client.del(errorKey)
|
||||
@@ -1864,6 +1878,10 @@ class ClaudeAccountService {
|
||||
delete account.errorMessage
|
||||
delete account.tempErrorAt
|
||||
await redis.setClaudeAccount(account.id, account)
|
||||
|
||||
// 显式从 Redis 中删除这些字段(因为 HSET 不会删除现有字段)
|
||||
await redis.client.hdel(`claude:account:${account.id}`, 'errorMessage', 'tempErrorAt')
|
||||
|
||||
// 同时清除500错误计数
|
||||
await this.clearInternalErrors(account.id)
|
||||
cleanedCount++
|
||||
@@ -1951,6 +1969,52 @@ class ClaudeAccountService {
|
||||
// 保存更新后的账户数据
|
||||
await redis.setClaudeAccount(accountId, updatedAccountData)
|
||||
|
||||
// 设置 5 分钟后自动恢复(一次性定时器)
|
||||
setTimeout(
|
||||
async () => {
|
||||
try {
|
||||
const account = await redis.getClaudeAccount(accountId)
|
||||
if (account && account.status === 'temp_error' && account.tempErrorAt) {
|
||||
// 验证是否确实过了 5 分钟(防止重复定时器)
|
||||
const tempErrorAt = new Date(account.tempErrorAt)
|
||||
const now = new Date()
|
||||
const minutesSince = (now - tempErrorAt) / (1000 * 60)
|
||||
|
||||
if (minutesSince >= 5) {
|
||||
// 恢复账户
|
||||
account.status = 'active'
|
||||
account.schedulable = 'true'
|
||||
delete account.errorMessage
|
||||
delete account.tempErrorAt
|
||||
|
||||
await redis.setClaudeAccount(accountId, account)
|
||||
|
||||
// 显式删除 Redis 字段
|
||||
await redis.client.hdel(
|
||||
`claude:account:${accountId}`,
|
||||
'errorMessage',
|
||||
'tempErrorAt'
|
||||
)
|
||||
|
||||
// 清除 500 错误计数
|
||||
await this.clearInternalErrors(accountId)
|
||||
|
||||
logger.success(
|
||||
`✅ Auto-recovered temp_error after 5 minutes: ${account.name} (${accountId})`
|
||||
)
|
||||
} else {
|
||||
logger.debug(
|
||||
`⏰ Temp error timer triggered but only ${minutesSince.toFixed(1)} minutes passed for ${account.name} (${accountId})`
|
||||
)
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`❌ Failed to auto-recover temp_error account ${accountId}:`, error)
|
||||
}
|
||||
},
|
||||
6 * 60 * 1000
|
||||
) // 6 分钟后执行,确保已过 5 分钟
|
||||
|
||||
// 如果有sessionHash,删除粘性会话映射
|
||||
if (sessionHash) {
|
||||
await redis.client.del(`sticky_session:${sessionHash}`)
|
||||
|
||||
@@ -376,9 +376,11 @@
|
||||
? 'bg-orange-100 text-orange-800'
|
||||
: account.status === 'unauthorized'
|
||||
? 'bg-red-100 text-red-800'
|
||||
: account.isActive
|
||||
? 'bg-green-100 text-green-800'
|
||||
: 'bg-red-100 text-red-800'
|
||||
: account.status === 'temp_error'
|
||||
? 'bg-orange-100 text-orange-800'
|
||||
: account.isActive
|
||||
? 'bg-green-100 text-green-800'
|
||||
: 'bg-red-100 text-red-800'
|
||||
]"
|
||||
>
|
||||
<div
|
||||
@@ -388,9 +390,11 @@
|
||||
? 'bg-orange-500'
|
||||
: account.status === 'unauthorized'
|
||||
? 'bg-red-500'
|
||||
: account.isActive
|
||||
? 'bg-green-500'
|
||||
: 'bg-red-500'
|
||||
: account.status === 'temp_error'
|
||||
? 'bg-orange-500'
|
||||
: account.isActive
|
||||
? 'bg-green-500'
|
||||
: 'bg-red-500'
|
||||
]"
|
||||
/>
|
||||
{{
|
||||
@@ -398,9 +402,11 @@
|
||||
? '已封锁'
|
||||
: account.status === 'unauthorized'
|
||||
? '异常'
|
||||
: account.isActive
|
||||
? '正常'
|
||||
: '异常'
|
||||
: account.status === 'temp_error'
|
||||
? '临时异常'
|
||||
: account.isActive
|
||||
? '正常'
|
||||
: '异常'
|
||||
}}
|
||||
</span>
|
||||
<span
|
||||
@@ -1630,6 +1636,9 @@ const getSchedulableReason = (account) => {
|
||||
if (account.status === 'unauthorized') {
|
||||
return '认证失败(401错误)'
|
||||
}
|
||||
if (account.status === 'temp_error' && account.errorMessage) {
|
||||
return account.errorMessage
|
||||
}
|
||||
if (account.status === 'error' && account.errorMessage) {
|
||||
return account.errorMessage
|
||||
}
|
||||
@@ -1668,6 +1677,8 @@ const getAccountStatusText = (account) => {
|
||||
account.rateLimitStatus === 'limited'
|
||||
)
|
||||
return '限流中'
|
||||
// 检查是否临时错误
|
||||
if (account.status === 'temp_error') return '临时异常'
|
||||
// 检查是否错误
|
||||
if (account.status === 'error' || !account.isActive) return '错误'
|
||||
// 检查是否可调度
|
||||
@@ -1692,6 +1703,9 @@ const getAccountStatusClass = (account) => {
|
||||
) {
|
||||
return 'bg-orange-100 text-orange-800'
|
||||
}
|
||||
if (account.status === 'temp_error') {
|
||||
return 'bg-orange-100 text-orange-800'
|
||||
}
|
||||
if (account.status === 'error' || !account.isActive) {
|
||||
return 'bg-red-100 text-red-800'
|
||||
}
|
||||
@@ -1717,6 +1731,9 @@ const getAccountStatusDotClass = (account) => {
|
||||
) {
|
||||
return 'bg-orange-500'
|
||||
}
|
||||
if (account.status === 'temp_error') {
|
||||
return 'bg-orange-500'
|
||||
}
|
||||
if (account.status === 'error' || !account.isActive) {
|
||||
return 'bg-red-500'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user