feat: 改进5xx错误熔断机制和重置状态功能

## 熔断机制优化
- 将5xx错误阈值从3次提升到10次,减少误触发
- 缩短临时错误恢复时间从60分钟到5分钟
- 支持所有5xx状态码(500-599)的统一处理

## 重置状态功能完善
后端 resetAccountStatus 新增清除:
- tempErrorAt 字段 (temp_error状态)
- sessionWindowStart/sessionWindowEnd 字段
- 5xx_errors Redis计数键

前端优化:
- 重置成功后强制刷新 loadAccounts(true)
- 避免缓存导致的状态显示不一致

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
sczheng189
2025-09-01 21:39:39 +08:00
parent f4f88091c1
commit f2c2bdf6d6
3 changed files with 12 additions and 4 deletions

View File

@@ -1704,6 +1704,9 @@ class ClaudeAccountService {
delete updatedAccountData.rateLimitedAt delete updatedAccountData.rateLimitedAt
delete updatedAccountData.rateLimitStatus delete updatedAccountData.rateLimitStatus
delete updatedAccountData.rateLimitEndAt delete updatedAccountData.rateLimitEndAt
delete updatedAccountData.tempErrorAt
delete updatedAccountData.sessionWindowStart
delete updatedAccountData.sessionWindowEnd
// 保存更新后的账户数据 // 保存更新后的账户数据
await redis.setClaudeAccount(accountId, updatedAccountData) await redis.setClaudeAccount(accountId, updatedAccountData)
@@ -1716,6 +1719,10 @@ class ClaudeAccountService {
const rateLimitKey = `ratelimit:${accountId}` const rateLimitKey = `ratelimit:${accountId}`
await redis.client.del(rateLimitKey) await redis.client.del(rateLimitKey)
// 清除5xx错误计数
const serverErrorKey = `claude_account:${accountId}:5xx_errors`
await redis.client.del(serverErrorKey)
logger.info( logger.info(
`✅ Successfully reset all error states for account ${accountData.name} (${accountId})` `✅ Successfully reset all error states for account ${accountData.name} (${accountId})`
) )
@@ -1740,7 +1747,7 @@ class ClaudeAccountService {
try { try {
const accounts = await redis.getAllClaudeAccounts() const accounts = await redis.getAllClaudeAccounts()
let cleanedCount = 0 let cleanedCount = 0
const TEMP_ERROR_RECOVERY_MINUTES = 60 // 临时错误状态恢复时间(分钟) const TEMP_ERROR_RECOVERY_MINUTES = 5 // 临时错误状态恢复时间(分钟)
for (const account of accounts) { for (const account of accounts) {
if (account.status === 'temp_error' && account.tempErrorAt) { if (account.status === 'temp_error' && account.tempErrorAt) {

View File

@@ -207,7 +207,7 @@ class ClaudeRelayService {
logger.info( logger.info(
`🔥 Account ${accountId} has ${errorCount} consecutive 5xx errors in the last 5 minutes` `🔥 Account ${accountId} has ${errorCount} consecutive 5xx errors in the last 5 minutes`
) )
if (errorCount >= 3) { if (errorCount > 10) {
logger.error( logger.error(
`❌ Account ${accountId} exceeded 5xx error threshold (${errorCount} errors), marking as temp_error` `❌ Account ${accountId} exceeded 5xx error threshold (${errorCount} errors), marking as temp_error`
) )
@@ -915,7 +915,7 @@ class ClaudeRelayService {
logger.info( logger.info(
`🔥 [Stream] Account ${accountId} has ${errorCount} consecutive 5xx errors in the last 5 minutes` `🔥 [Stream] Account ${accountId} has ${errorCount} consecutive 5xx errors in the last 5 minutes`
) )
if (errorCount >= 3) { if (errorCount > 10) {
logger.error( logger.error(
`❌ [Stream] Account ${accountId} exceeded 5xx error threshold (${errorCount} errors), marking as temp_error` `❌ [Stream] Account ${accountId} exceeded 5xx error threshold (${errorCount} errors), marking as temp_error`
) )

View File

@@ -1323,7 +1323,8 @@ const resetAccountStatus = async (account) => {
if (data.success) { if (data.success) {
showToast('账户状态已重置', 'success') showToast('账户状态已重置', 'success')
loadAccounts() // 强制刷新,绕过前端缓存,确保最终一致性
loadAccounts(true)
} else { } else {
showToast(data.message || '状态重置失败', 'error') showToast(data.message || '状态重置失败', 'error')
} }