From b4d7ed06c5769d92203d30473cf0f76e7487ffda Mon Sep 17 00:00:00 2001 From: shaw Date: Sun, 28 Sep 2025 23:30:41 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D5=E5=B0=8F=E6=97=B6?= =?UTF-8?q?=E9=99=90=E5=88=B6=E8=A2=AB=E5=81=9C=E6=AD=A2=E8=B0=83=E5=BA=A6?= =?UTF-8?q?=E6=9C=AA=E6=81=A2=E5=A4=8D=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/services/claudeAccountService.js | 61 ++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/services/claudeAccountService.js b/src/services/claudeAccountService.js index 75d3ed29..5e7dfca9 100644 --- a/src/services/claudeAccountService.js +++ b/src/services/claudeAccountService.js @@ -599,6 +599,7 @@ class ClaudeAccountService { 'unifiedClientId' ] const updatedData = { ...accountData } + let shouldClearAutoStopFields = false // 检查是否新增了 refresh token const oldRefreshToken = this._decryptSensitiveData(accountData.refreshToken) @@ -669,6 +670,7 @@ class ClaudeAccountService { // 兼容旧的标记(逐步迁移) delete updatedData.autoStoppedAt delete updatedData.stoppedReason + shouldClearAutoStopFields = true // 如果是手动启用调度,记录日志 if (updates.schedulable === true || updates.schedulable === 'true') { @@ -700,6 +702,18 @@ class ClaudeAccountService { await redis.setClaudeAccount(accountId, updatedData) + if (shouldClearAutoStopFields) { + const fieldsToRemove = [ + 'rateLimitAutoStopped', + 'fiveHourAutoStopped', + 'fiveHourStoppedAt', + 'tempErrorAutoStopped', + 'autoStoppedAt', + 'stoppedReason' + ] + await this._removeAccountFields(accountId, fieldsToRemove, 'manual_schedule_update') + } + logger.success(`📝 Updated Claude account: ${accountId}`) return { success: true } @@ -1399,6 +1413,9 @@ class ClaudeAccountService { const now = new Date() const currentTime = now.getTime() + let shouldClearSessionStatus = false + let shouldClearFiveHourFlags = false + // 检查当前是否有活跃的会话窗口 if (accountData.sessionWindowStart && accountData.sessionWindowEnd) { const windowEnd = new Date(accountData.sessionWindowEnd).getTime() @@ -1429,6 +1446,7 @@ class ClaudeAccountService { if (accountData.sessionWindowStatus) { delete accountData.sessionWindowStatus delete accountData.sessionWindowStatusUpdatedAt + shouldClearSessionStatus = true } // 如果账户因为5小时限制被自动停止,现在恢复调度 @@ -1439,6 +1457,7 @@ class ClaudeAccountService { accountData.schedulable = 'true' delete accountData.fiveHourAutoStopped delete accountData.fiveHourStoppedAt + shouldClearFiveHourFlags = true // 发送Webhook通知 try { @@ -1457,6 +1476,17 @@ class ClaudeAccountService { } } + if (shouldClearSessionStatus || shouldClearFiveHourFlags) { + const fieldsToRemove = [] + if (shouldClearFiveHourFlags) { + fieldsToRemove.push('fiveHourAutoStopped', 'fiveHourStoppedAt') + } + if (shouldClearSessionStatus) { + fieldsToRemove.push('sessionWindowStatus', 'sessionWindowStatusUpdatedAt') + } + await this._removeAccountFields(accountId, fieldsToRemove, 'session_window_refresh') + } + logger.info( `🕐 Created new session window for account ${accountData.name} (${accountId}): ${windowStart.toISOString()} - ${windowEnd.toISOString()} (from current time)` ) @@ -2486,6 +2516,12 @@ class ClaudeAccountService { // 保存更新 await redis.setClaudeAccount(account.id, updatedAccountData) + const fieldsToRemove = ['fiveHourAutoStopped', 'fiveHourStoppedAt'] + if (newWindowStart && newWindowEnd) { + fieldsToRemove.push('sessionWindowStatus', 'sessionWindowStatusUpdatedAt') + } + await this._removeAccountFields(account.id, fieldsToRemove, 'five_hour_recovery_task') + result.recovered++ result.accounts.push({ id: latestAccount.id, @@ -2541,6 +2577,31 @@ class ClaudeAccountService { throw error } } + + async _removeAccountFields(accountId, fields = [], context = 'general_cleanup') { + if (!Array.isArray(fields) || fields.length === 0) { + return + } + + const filteredFields = fields.filter((field) => typeof field === 'string' && field.trim()) + if (filteredFields.length === 0) { + return + } + + const accountKey = `claude:account:${accountId}` + + try { + await redis.client.hdel(accountKey, ...filteredFields) + logger.debug( + `🧹 已在 ${context} 阶段为账号 ${accountId} 删除字段 [${filteredFields.join(', ')}]` + ) + } catch (error) { + logger.error( + `❌ 无法在 ${context} 阶段为账号 ${accountId} 删除字段 [${filteredFields.join(', ')}]:`, + error + ) + } + } } module.exports = new ClaudeAccountService()