From 4c2660a2d387e3cf120f7f7f4ece88298fa1af57 Mon Sep 17 00:00:00 2001 From: Edric Li Date: Tue, 9 Sep 2025 02:33:50 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E4=B8=93=E5=B1=9E?= =?UTF-8?q?=E8=B4=A6=E5=8F=B7=E5=81=9C=E6=AD=A2=E8=B0=83=E5=BA=A6=E5=90=8E?= =?UTF-8?q?=E4=BB=8D=E8=83=BD=E4=BD=BF=E7=94=A8=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 selectAccountForApiKey 方法中为所有专属账号类型添加 schedulable 检查 - 在 _getAllAvailableAccounts 方法中为所有专属账号类型添加 schedulable 检查 - 改进日志输出,显示账号不可用的具体原因(isActive、status、schedulable 状态) 问题描述: 当 Claude Console/OAuth/Bedrock 账号设置为专属账号并停止调度(schedulable=false)后, 系统仍然会使用该账号,没有正确回退到账号池。 修复内容: 1. Claude OAuth 账号:添加 this._isSchedulable(boundAccount.schedulable) 检查 2. Claude Console 账号:添加 this._isSchedulable(boundConsoleAccount.schedulable) 检查 3. Bedrock 账号:添加 this._isSchedulable(boundBedrockAccountResult.data.schedulable) 检查 兼容性: _isSchedulable 方法已处理向后兼容,当 schedulable 字段为 undefined/null 时默认返回 true 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/services/unifiedClaudeScheduler.js | 44 +++++++++++++++++++------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/src/services/unifiedClaudeScheduler.js b/src/services/unifiedClaudeScheduler.js index 7bceb040..50e92e33 100644 --- a/src/services/unifiedClaudeScheduler.js +++ b/src/services/unifiedClaudeScheduler.js @@ -107,7 +107,12 @@ class UnifiedClaudeScheduler { // 普通专属账户 const boundAccount = await redis.getClaudeAccount(apiKeyData.claudeAccountId) - if (boundAccount && boundAccount.isActive === 'true' && boundAccount.status !== 'error') { + if ( + boundAccount && + boundAccount.isActive === 'true' && + boundAccount.status !== 'error' && + this._isSchedulable(boundAccount.schedulable) + ) { logger.info( `🎯 Using bound dedicated Claude OAuth account: ${boundAccount.name} (${apiKeyData.claudeAccountId}) for API key ${apiKeyData.name}` ) @@ -117,7 +122,7 @@ class UnifiedClaudeScheduler { } } else { logger.warn( - `⚠️ Bound Claude OAuth account ${apiKeyData.claudeAccountId} is not available, falling back to pool` + `⚠️ Bound Claude OAuth account ${apiKeyData.claudeAccountId} is not available (isActive: ${boundAccount?.isActive}, status: ${boundAccount?.status}, schedulable: ${boundAccount?.schedulable}), falling back to pool` ) } } @@ -130,7 +135,8 @@ class UnifiedClaudeScheduler { if ( boundConsoleAccount && boundConsoleAccount.isActive === true && - boundConsoleAccount.status === 'active' + boundConsoleAccount.status === 'active' && + this._isSchedulable(boundConsoleAccount.schedulable) ) { logger.info( `🎯 Using bound dedicated Claude Console account: ${boundConsoleAccount.name} (${apiKeyData.claudeConsoleAccountId}) for API key ${apiKeyData.name}` @@ -141,7 +147,7 @@ class UnifiedClaudeScheduler { } } else { logger.warn( - `⚠️ Bound Claude Console account ${apiKeyData.claudeConsoleAccountId} is not available, falling back to pool` + `⚠️ Bound Claude Console account ${apiKeyData.claudeConsoleAccountId} is not available (isActive: ${boundConsoleAccount?.isActive}, status: ${boundConsoleAccount?.status}, schedulable: ${boundConsoleAccount?.schedulable}), falling back to pool` ) } } @@ -151,7 +157,11 @@ class UnifiedClaudeScheduler { const boundBedrockAccountResult = await bedrockAccountService.getAccount( apiKeyData.bedrockAccountId ) - if (boundBedrockAccountResult.success && boundBedrockAccountResult.data.isActive === true) { + if ( + boundBedrockAccountResult.success && + boundBedrockAccountResult.data.isActive === true && + this._isSchedulable(boundBedrockAccountResult.data.schedulable) + ) { logger.info( `🎯 Using bound dedicated Bedrock account: ${boundBedrockAccountResult.data.name} (${apiKeyData.bedrockAccountId}) for API key ${apiKeyData.name}` ) @@ -161,7 +171,7 @@ class UnifiedClaudeScheduler { } } else { logger.warn( - `⚠️ Bound Bedrock account ${apiKeyData.bedrockAccountId} is not available, falling back to pool` + `⚠️ Bound Bedrock account ${apiKeyData.bedrockAccountId} is not available (isActive: ${boundBedrockAccountResult?.data?.isActive}, schedulable: ${boundBedrockAccountResult?.data?.schedulable}), falling back to pool` ) } } @@ -251,7 +261,8 @@ class UnifiedClaudeScheduler { boundAccount.isActive === 'true' && boundAccount.status !== 'error' && boundAccount.status !== 'blocked' && - boundAccount.status !== 'temp_error' + boundAccount.status !== 'temp_error' && + this._isSchedulable(boundAccount.schedulable) ) { const isRateLimited = await claudeAccountService.isAccountRateLimited(boundAccount.id) if (!isRateLimited) { @@ -269,7 +280,9 @@ class UnifiedClaudeScheduler { ] } } else { - logger.warn(`⚠️ Bound Claude OAuth account ${apiKeyData.claudeAccountId} is not available`) + logger.warn( + `⚠️ Bound Claude OAuth account ${apiKeyData.claudeAccountId} is not available (isActive: ${boundAccount?.isActive}, status: ${boundAccount?.status}, schedulable: ${boundAccount?.schedulable})` + ) } } @@ -281,7 +294,8 @@ class UnifiedClaudeScheduler { if ( boundConsoleAccount && boundConsoleAccount.isActive === true && - boundConsoleAccount.status === 'active' + boundConsoleAccount.status === 'active' && + this._isSchedulable(boundConsoleAccount.schedulable) ) { // 主动触发一次额度检查 try { @@ -317,7 +331,7 @@ class UnifiedClaudeScheduler { } } else { logger.warn( - `⚠️ Bound Claude Console account ${apiKeyData.claudeConsoleAccountId} is not available` + `⚠️ Bound Claude Console account ${apiKeyData.claudeConsoleAccountId} is not available (isActive: ${boundConsoleAccount?.isActive}, status: ${boundConsoleAccount?.status}, schedulable: ${boundConsoleAccount?.schedulable})` ) } } @@ -327,7 +341,11 @@ class UnifiedClaudeScheduler { const boundBedrockAccountResult = await bedrockAccountService.getAccount( apiKeyData.bedrockAccountId ) - if (boundBedrockAccountResult.success && boundBedrockAccountResult.data.isActive === true) { + if ( + boundBedrockAccountResult.success && + boundBedrockAccountResult.data.isActive === true && + this._isSchedulable(boundBedrockAccountResult.data.schedulable) + ) { logger.info( `🎯 Using bound dedicated Bedrock account: ${boundBedrockAccountResult.data.name} (${apiKeyData.bedrockAccountId})` ) @@ -341,7 +359,9 @@ class UnifiedClaudeScheduler { } ] } else { - logger.warn(`⚠️ Bound Bedrock account ${apiKeyData.bedrockAccountId} is not available`) + logger.warn( + `⚠️ Bound Bedrock account ${apiKeyData.bedrockAccountId} is not available (isActive: ${boundBedrockAccountResult?.data?.isActive}, schedulable: ${boundBedrockAccountResult?.data?.schedulable})` + ) } }