Merge PR #507: add rate limit recovery notifications

This commit is contained in:
shaw
2025-10-03 22:25:46 +08:00
4 changed files with 77 additions and 17 deletions

View File

@@ -490,20 +490,29 @@ class ClaudeConsoleAccountService {
errorMessage: ''
}
const hadAutoStop = accountData.rateLimitAutoStopped === 'true'
// 只恢复因限流而自动停止的账户
if (accountData.rateLimitAutoStopped === 'true' && accountData.schedulable === 'false') {
if (hadAutoStop && accountData.schedulable === 'false') {
updateData.schedulable = 'true' // 恢复调度
// 删除限流自动停止标记
await client.hdel(accountKey, 'rateLimitAutoStopped')
logger.info(
`✅ Auto-resuming scheduling for Claude Console account ${accountId} after rate limit cleared`
)
}
if (hadAutoStop) {
await client.hdel(accountKey, 'rateLimitAutoStopped')
}
await client.hset(accountKey, updateData)
logger.success(`✅ Rate limit removed and account re-enabled: ${accountId}`)
}
} else {
if (await client.hdel(accountKey, 'rateLimitAutoStopped')) {
logger.info(
` Removed stale auto-stop flag for Claude Console account ${accountId} during rate limit recovery`
)
}
logger.success(`✅ Rate limit removed for Claude Console account: ${accountId}`)
}

View File

@@ -110,9 +110,6 @@ class RateLimitCleanupService {
)
}
// 清空已清理账户列表
this.clearedAccounts = []
// 记录错误
const allErrors = [
...results.openai.errors,
@@ -125,6 +122,8 @@ class RateLimitCleanupService {
} catch (error) {
logger.error('❌ Rate limit cleanup failed:', error)
} finally {
// 确保无论成功或失败都重置列表,避免重复通知
this.clearedAccounts = []
this.isRunning = false
}
}
@@ -199,8 +198,12 @@ class RateLimitCleanupService {
typeof account.rateLimitStatus === 'object' &&
account.rateLimitStatus.status === 'limited')
const autoStopped = account.rateLimitAutoStopped === 'true'
const needsAutoStopRecovery =
autoStopped && (account.rateLimitEndAt || account.schedulable === 'false')
// 检查所有可能处于限流状态的账号,包括自动停止的账号
if (isRateLimited || account.rateLimitedAt || account.rateLimitAutoStopped === 'true') {
if (isRateLimited || account.rateLimitedAt || needsAutoStopRecovery) {
result.checked++
try {
@@ -208,6 +211,9 @@ class RateLimitCleanupService {
const isStillLimited = await claudeAccountService.isAccountRateLimited(account.id)
if (!isStillLimited) {
if (!isRateLimited && autoStopped) {
await claudeAccountService.removeAccountRateLimit(account.id)
}
result.cleared++
logger.info(
`🧹 Auto-cleared expired rate limit for Claude account: ${account.name} (${account.id})`
@@ -286,10 +292,13 @@ class RateLimitCleanupService {
typeof account.rateLimitStatus === 'object' &&
account.rateLimitStatus.status === 'limited')
const autoStopped = account.rateLimitAutoStopped === 'true'
const needsAutoStopRecovery = autoStopped && account.schedulable === 'false'
// 检查两种状态字段rateLimitStatus 和 status
const hasStatusRateLimited = account.status === 'rate_limited'
if (isRateLimited || hasStatusRateLimited) {
if (isRateLimited || hasStatusRateLimited || needsAutoStopRecovery) {
result.checked++
try {
@@ -299,6 +308,9 @@ class RateLimitCleanupService {
)
if (!isStillLimited) {
if (!isRateLimited && autoStopped) {
await claudeConsoleAccountService.removeAccountRateLimit(account.id)
}
result.cleared++
// 如果 status 字段是 rate_limited需要额外清理

View File

@@ -18,7 +18,17 @@ class WebhookConfigService {
// 返回默认配置
return this.getDefaultConfig()
}
return JSON.parse(configStr)
const storedConfig = JSON.parse(configStr)
const defaultConfig = this.getDefaultConfig()
// 合并默认通知类型,确保新增类型有默认值
storedConfig.notificationTypes = {
...defaultConfig.notificationTypes,
...(storedConfig.notificationTypes || {})
}
return storedConfig
} catch (error) {
logger.error('获取webhook配置失败:', error)
return this.getDefaultConfig()
@@ -30,6 +40,13 @@ class WebhookConfigService {
*/
async saveConfig(config) {
try {
const defaultConfig = this.getDefaultConfig()
config.notificationTypes = {
...defaultConfig.notificationTypes,
...(config.notificationTypes || {})
}
// 验证配置
this.validateConfig(config)
@@ -312,6 +329,7 @@ class WebhookConfigService {
quotaWarning: true, // 配额警告
systemError: true, // 系统错误
securityAlert: true, // 安全警报
rateLimitRecovery: true, // 限流恢复
test: true // 测试通知
},
retrySettings: {