fix(provider): 修复令牌刷新机制中的并发和状态问题
修复 provider-pool-manager 中令牌刷新逻辑的多个问题: - 将最大刷新次数从 3 更正为 5 以匹配注释 - 添加防并发机制,避免同一节点重复刷新 - 刷新成功后统一重置 needsRefresh、refreshCount 并记录 lastRefreshTime - 在 Grok 服务中添加重置刷新状态的调用 - 防止 30 秒内的重复刷新请求 这些更改解决了因 401 错误滞后导致的重复刷新、状态不一致以及节点被过早标记为不健康的问题。
This commit is contained in:
parent
c5d475c7e0
commit
9bbde40e4c
3 changed files with 33 additions and 7 deletions
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
|||
2.11.8
|
||||
2.11.9
|
||||
|
|
|
|||
|
|
@ -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.`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
// 标记为健康,以便立即投入使用
|
||||
|
|
|
|||
Loading…
Reference in a new issue