fix(provider): 优化节点刷新逻辑
- 修改节点刷新逻辑,当健康节点少于5个时立即刷新 - 移除刷新时的随机延迟以避免并发问题 - 更新Claude Kiro版本号至0.8.140 - 在初始化API服务时添加isReady参数控制预热逻辑 - 在modal.js中排除更多字段
This commit is contained in:
parent
f8faee93fc
commit
fe131b33d2
5 changed files with 30 additions and 45 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
// 增加刷新计数
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -674,7 +674,7 @@ function getFieldOrder(provider) {
|
|||
const excludedFields = [
|
||||
'isHealthy', 'lastUsed', 'usageCount', 'errorCount', 'lastErrorTime',
|
||||
'uuid', 'isDisabled', 'lastHealthCheckTime', 'lastHealthCheckModel', 'lastErrorMessage',
|
||||
'notSupportedModels'
|
||||
'notSupportedModels', 'refreshCount', 'needsRefresh'
|
||||
];
|
||||
|
||||
// 从 getProviderTypeFields 获取字段顺序映射
|
||||
|
|
|
|||
Loading…
Reference in a new issue