fix(provider): 优化节点刷新逻辑

- 修改节点刷新逻辑,当健康节点少于5个时立即刷新
- 移除刷新时的随机延迟以避免并发问题
- 更新Claude Kiro版本号至0.8.140
- 在初始化API服务时添加isReady参数控制预热逻辑
- 在modal.js中排除更多字段
This commit is contained in:
hex2077 2026-01-20 00:10:04 +08:00
parent f8faee93fc
commit fe131b33d2
5 changed files with 30 additions and 45 deletions

View file

@ -31,7 +31,7 @@ const KIRO_CONSTANTS = {
AXIOS_TIMEOUT: 120000, // 2 minutes timeout for normal requests
TOKEN_REFRESH_TIMEOUT: 15000, // 15 seconds timeout for token refresh (shorter to avoid blocking)
USER_AGENT: 'KiroIDE',
KIRO_VERSION: '0.7.5',
KIRO_VERSION: '0.8.140',
CONTENT_TYPE_JSON: 'application/json',
ACCEPT_JSON: 'application/json',
AUTH_METHOD_SOCIAL: 'social',
@ -403,7 +403,7 @@ export class KiroApiService {
// 配置 HTTP/HTTPS agent 限制连接池大小,避免资源泄漏
const httpAgent = new http.Agent({
keepAlive: true,
maxSockets: 100, // 每个主机最多 10 个连接
maxSockets: 100, // 每个主机最多 100 个连接
maxFreeSockets: 5, // 最多保留 5 个空闲连接
timeout: KIRO_CONSTANTS.AXIOS_TIMEOUT,
});
@ -2735,7 +2735,7 @@ async saveCredentialsToFile(filePath, newData) {
}
const fullUrl = `${usageLimitsUrl}?${params.toString()}`;
// 构建请求头
// 动态生成 headers
const machineId = generateMachineIdFromConfig({
uuid: this.uuid,
profileArn: this.profileArn,

View file

@ -108,32 +108,7 @@ export class ProviderPoolManager {
if (configPath && fs.existsSync(configPath)) {
try {
const fileContent = fs.readFileSync(configPath, 'utf8');
const data = JSON.parse(fileContent);
// 获取对应的适配器
const tempConfig = {
...config,
MODEL_PROVIDER: providerType
};
const serviceAdapter = getServiceAdapter(tempConfig);
// 调用提供商适配器内的 isExpiryDateNear 方法
let needsRefresh = false;
if (typeof serviceAdapter.isExpiryDateNear === 'function') {
// 适配器内部自行判断,不传参
needsRefresh = serviceAdapter.isExpiryDateNear();
this._log('info', `Node ${providerStatus.uuid} (${providerType}) isExpiryDateNear: ${needsRefresh}`);
} else {
// 兜底逻辑:如果适配器没实现,使用配置数据进行判断
const expiryDate = data.expiry_date || data.expires_at || data.expiry;
if (expiryDate) {
const expiry = new Date(expiryDate).getTime();
needsRefresh = (expiry - Date.now()) < 24 * 60 * 60 * 1000;
}
}
if (needsRefresh) {
if (true) {
this._log('warn', `Node ${providerStatus.uuid} (${providerType}) is near expiration. Enqueuing refresh...`);
this._enqueueRefresh(providerType, providerStatus);
}
@ -141,7 +116,7 @@ export class ProviderPoolManager {
this._log('error', `Failed to check expiry for node ${providerStatus.uuid}: ${err.message}`);
}
} else {
this._log('debug', `Node ${providerStatus.uuid} (${providerType}) has no valid config file path or file does not exist.`);
this._log('debug', `Node ${providerStatus.uuid} (${providerType}) has no valid config file path or file does not exist.`);
}
}
}
@ -203,6 +178,14 @@ export class ProviderPoolManager {
return;
}
// 判断提供商池内的总可用节点数小于5个时不等待缓冲直接加入刷新队列
const healthyCount = this.getHealthyCount(providerType);
if (healthyCount < 5) {
this._log('info', `Provider ${providerType} has only ${healthyCount} healthy nodes. Bypassing buffer and enqueuing refresh for ${uuid} immediately.`);
this._enqueueRefreshImmediate(providerType, providerStatus, force);
return;
}
// 初始化缓冲队列
if (!this.refreshBufferQueues[providerType]) {
this.refreshBufferQueues[providerType] = new Map(); // 使用 Map 自动去重
@ -383,9 +366,9 @@ export class ProviderPoolManager {
}
// 添加5秒内的随机等待时间避免并发刷新时的冲突
const randomDelay = Math.floor(Math.random() * 5000);
this._log('info', `Starting token refresh for node ${providerStatus.uuid} (${providerType}) with ${randomDelay}ms delay`);
await new Promise(resolve => setTimeout(resolve, randomDelay));
// const randomDelay = Math.floor(Math.random() * 5000);
// this._log('info', `Starting token refresh for node ${providerStatus.uuid} (${providerType}) with ${randomDelay}ms delay`);
// await new Promise(resolve => setTimeout(resolve, randomDelay));
try {
// 增加刷新计数

View file

@ -242,7 +242,7 @@ async function startServer() {
}
// Initialize API services
const services = await initApiService(CONFIG);
const services = await initApiService(CONFIG, true);
// Initialize UI management features
initializeUIManagement(CONFIG);

View file

@ -165,7 +165,7 @@ async function scanProviderDirectory(dirPath, linkedPaths, newProviders, options
* @param {Object} config - The server configuration
* @returns {Promise<Object>} The initialized services
*/
export async function initApiService(config) {
export async function initApiService(config, isReady = false) {
if (config.providerPools && Object.keys(config.providerPools).length > 0) {
providerPoolManager = new ProviderPoolManager(config.providerPools, {
@ -175,16 +175,18 @@ export async function initApiService(config) {
});
console.log('[Initialization] ProviderPoolManager initialized with configured pools.');
// --- V2: 触发系统预热 ---
// 预热逻辑是异步的,不会阻塞服务器启动
providerPoolManager.warmupNodes().catch(err => {
console.error(`[Initialization] Warmup failed: ${err.message}`);
});
if(isReady){
// --- V2: 触发系统预热 ---
// 预热逻辑是异步的,不会阻塞服务器启动
providerPoolManager.warmupNodes().catch(err => {
console.error(`[Initialization] Warmup failed: ${err.message}`);
});
// 检查并刷新即将过期的节点(异步调用,不阻塞启动)
providerPoolManager.checkAndRefreshExpiringNodes().catch(err => {
console.error(`[Initialization] Check and refresh expiring nodes failed: ${err.message}`);
});
// 检查并刷新即将过期的节点(异步调用,不阻塞启动)
providerPoolManager.checkAndRefreshExpiringNodes().catch(err => {
console.error(`[Initialization] Check and refresh expiring nodes failed: ${err.message}`);
});
}
// 健康检查将在服务器完全启动后执行
} else {

View file

@ -674,7 +674,7 @@ function getFieldOrder(provider) {
const excludedFields = [
'isHealthy', 'lastUsed', 'usageCount', 'errorCount', 'lastErrorTime',
'uuid', 'isDisabled', 'lastHealthCheckTime', 'lastHealthCheckModel', 'lastErrorMessage',
'notSupportedModels'
'notSupportedModels', 'refreshCount', 'needsRefresh'
];
// 从 getProviderTypeFields 获取字段顺序映射