From 9bbde40e4cecbf6f83fe14b1a8c9a66f5a0aa629 Mon Sep 17 00:00:00 2001 From: hex2077 Date: Thu, 26 Mar 2026 12:32:09 +0800 Subject: [PATCH] =?UTF-8?q?fix(provider):=20=E4=BF=AE=E5=A4=8D=E4=BB=A4?= =?UTF-8?q?=E7=89=8C=E5=88=B7=E6=96=B0=E6=9C=BA=E5=88=B6=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=E5=B9=B6=E5=8F=91=E5=92=8C=E7=8A=B6=E6=80=81=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复 provider-pool-manager 中令牌刷新逻辑的多个问题: - 将最大刷新次数从 3 更正为 5 以匹配注释 - 添加防并发机制,避免同一节点重复刷新 - 刷新成功后统一重置 needsRefresh、refreshCount 并记录 lastRefreshTime - 在 Grok 服务中添加重置刷新状态的调用 - 防止 30 秒内的重复刷新请求 这些更改解决了因 401 错误滞后导致的重复刷新、状态不一致以及节点被过早标记为不健康的问题。 --- VERSION | 2 +- src/providers/grok/grok-core.js | 13 +++++++++---- src/providers/provider-pool-manager.js | 25 +++++++++++++++++++++++-- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/VERSION b/VERSION index 9462efa..22ac5d0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.11.8 +2.11.9 diff --git a/src/providers/grok/grok-core.js b/src/providers/grok/grok-core.js index 5e854ad..ab9f92c 100644 --- a/src/providers/grok/grok-core.js +++ b/src/providers/grok/grok-core.js @@ -185,10 +185,15 @@ export class GrokApiService { } async refreshToken() { - try { - // await this.getUsageLimits(); return Promise.resolve(); - } catch (error) { - return Promise.reject(error); + try { + // await this.getUsageLimits(); return Promise.resolve(); + const poolManager = getProviderPoolManager(); + if (poolManager && this.uuid) { + poolManager.resetProviderRefreshStatus(MODEL_PROVIDER.GROK_CUSTOM, this.uuid); + } + } catch (error) { + logger.error('[Grok] Failed to initialize authentication:', error); + throw new Error(`Failed to refreshToken.`); } } diff --git a/src/providers/provider-pool-manager.js b/src/providers/provider-pool-manager.js index 6ec77ed..4a323fe 100644 --- a/src/providers/provider-pool-manager.js +++ b/src/providers/provider-pool-manager.js @@ -363,9 +363,9 @@ export class ProviderPoolManager { // 检查刷新次数是否已达上限(最大5次) const currentRefreshCount = config.refreshCount || 0; if (currentRefreshCount >= 5 && !force) { - this._log('warn', `Node ${providerStatus.uuid} has reached maximum refresh count (3), marking as unhealthy`); + this._log('warn', `Node ${providerStatus.uuid} has reached maximum refresh count (5), marking as unhealthy`); // 标记为不健康 - this.markProviderUnhealthyImmediately(providerType, config, 'Maximum refresh count (3) reached'); + this.markProviderUnhealthyImmediately(providerType, config, 'Maximum refresh count (5) reached'); return; } @@ -392,6 +392,11 @@ export class ProviderPoolManager { force ? await serviceAdapter.forceRefreshToken() : await serviceAdapter.refreshToken() const duration = Date.now() - startTime; this._log('info', `Token refresh successful for node ${providerStatus.uuid} (Duration: ${duration}ms)`); + + // 刷新成功,统一重置状态 + config.needsRefresh = false; + config.refreshCount = 0; + config.lastRefreshTime = Date.now(); // 记录最后刷新成功时间 } else { throw new Error(`refreshToken method not implemented for ${providerType}`); } @@ -1291,6 +1296,20 @@ export class ProviderPoolManager { const provider = this._findProvider(providerType, providerConfig.uuid); if (provider) { + // 防并发机制 A: 如果已经在刷新中,忽略请求 + if (this.refreshingUuids.has(provider.uuid)) { + this._log('debug', `Provider ${providerConfig.uuid} is already in refresh queue, ignoring duplicate request.`); + return; + } + + // 防并发机制 B: 如果 30 秒内刚刷新过,忽略请求(防止滞后的 401 错误导致重复刷新) + const now = Date.now(); + const lastRefreshTime = provider.config.lastRefreshTime || 0; + if (now - lastRefreshTime < 30000) { + this._log('info', `Provider ${providerConfig.uuid} was refreshed recently (${Math.round((now - lastRefreshTime)/1000)}s ago), ignoring refresh request.`); + return; + } + provider.config.needsRefresh = true; this._log('info', `Marked provider ${providerConfig.uuid} as needsRefresh. Enqueuing...`); @@ -1453,6 +1472,7 @@ export class ProviderPoolManager { provider.config.errorCount = 0; provider.config.refreshCount = 0; provider.config.needsRefresh = false; + provider.config.lastRefreshTime = Date.now(); // 标记为健康时也视为刚刷新完成 provider.config.lastErrorTime = null; provider.config.lastErrorMessage = null; provider.config._lastSelectionSeq = 0; @@ -1498,6 +1518,7 @@ export class ProviderPoolManager { if (provider) { provider.config.needsRefresh = false; provider.config.refreshCount = 0; + provider.config.lastRefreshTime = Date.now(); // 显式重置时也更新刷新时间 // 更新为可用 provider.config.lastHealthCheckTime = new Date().toISOString(); // 标记为健康,以便立即投入使用