refactor(provider-pool): 优化提供商池配置管理和健康检查逻辑

- 移除未使用的提供商池配置输入监听器
- 默认启用提供商池配置文件路径配置
- 修改健康检查方法参数名以更清晰表达意图
- 仅在明确要求时重置提供商使用计数
- 调整文件扫描深度以支持嵌套凭证目录结构
- 重载配置时更新提供商池管理器状态
This commit is contained in:
hex2077 2025-11-26 13:44:55 +08:00
parent 1c22b8c5c9
commit 9c114e2a7d
5 changed files with 37 additions and 18 deletions

View file

@ -270,9 +270,9 @@ export async function initializeConfig(args = process.argv.slice(2), configFileP
currentConfig.SYSTEM_PROMPT_CONTENT = await getSystemPromptFileContent(currentConfig.SYSTEM_PROMPT_FILE_PATH);
// 加载号池配置
// if (!currentConfig.PROVIDER_POOLS_FILE_PATH) {
// currentConfig.PROVIDER_POOLS_FILE_PATH = 'provider_pools.json';
// }
if (!currentConfig.PROVIDER_POOLS_FILE_PATH) {
currentConfig.PROVIDER_POOLS_FILE_PATH = 'provider_pools.json';
}
if (currentConfig.PROVIDER_POOLS_FILE_PATH) {
try {
const poolsData = await pfs.readFile(currentConfig.PROVIDER_POOLS_FILE_PATH, 'utf8');

View file

@ -166,7 +166,7 @@ export class ProviderPoolManager {
* @param {object} providerConfig - The configuration of the provider to mark.
* @param {boolean} isInit - Whether to reset usage count (optional, default: false).
*/
markProviderHealthy(providerType, providerConfig, isInit = false) {
markProviderHealthy(providerType, providerConfig, resetUsageCount = false) {
if (!providerConfig?.uuid) {
this._log('error', 'Invalid providerConfig in markProviderHealthy');
return;
@ -177,10 +177,11 @@ export class ProviderPoolManager {
provider.config.isHealthy = true;
provider.config.errorCount = 0;
provider.config.lastErrorTime = null;
if (isInit) {
// 只有在明确要求重置使用计数时才重置
if (resetUsageCount) {
provider.config.usageCount = 0;
}
this._log('info', `Marked provider as healthy: ${provider.config.uuid} for type ${providerType}`);
this._log('info', `Marked provider as healthy: ${provider.config.uuid} for type ${providerType}${resetUsageCount ? ' (usage count reset)' : ''}`);
this._debouncedSave(providerType);
}
@ -277,11 +278,13 @@ export class ProviderPoolManager {
if (isHealthy) {
if (!providerStatus.config.isHealthy) {
// Provider was unhealthy but is now healthy
this.markProviderHealthy(providerType, providerConfig, isInit);
// 恢复健康时不重置使用计数,保持原有值
this.markProviderHealthy(providerType, providerConfig);
this._log('info', `Health check for ${providerConfig.uuid} (${providerType}): Marked Healthy (actual check)`);
} else {
// Provider was already healthy and still is
this.markProviderHealthy(providerType, providerConfig, isInit);
// 只在初始化时重置使用计数
this.markProviderHealthy(providerType, providerConfig);
this._log('debug', `Health check for ${providerConfig.uuid} (${providerType}): Still Healthy`);
}
} else {

View file

@ -318,13 +318,18 @@ export async function serveStaticFiles(pathParam, res) {
* 动态导入config-manager并重新初始化配置
* @returns {Promise<Object>} 返回重载后的配置对象
*/
async function reloadConfig() {
async function reloadConfig(providerPoolManager) {
try {
// Import config manager dynamically
const { initializeConfig } = await import('./config-manager.js');
// Reload main config
const newConfig = await initializeConfig(process.argv.slice(2), 'config.json');
// Update provider pool manager if available
if (providerPoolManager) {
providerPoolManager.providerPools = newConfig.providerPools;
providerPoolManager.initializeProviderStatus();
}
// Update global CONFIG
Object.assign(CONFIG, newConfig);
@ -409,7 +414,17 @@ export async function handleUIApiRequests(method, pathParam, req, res, currentCo
const tempFilePath = req.file.path;
// 根据实际的provider移动文件到正确的目录
const targetDir = path.join(process.cwd(), 'configs', provider);
let targetDir = path.join(process.cwd(), 'configs', provider);
// 如果是kiro类型的凭证需要再包裹一层文件夹
if (provider === 'kiro') {
// 使用时间戳作为子文件夹名称,确保每个上传的文件都有独立的目录
const timestamp = Date.now();
const originalNameWithoutExt = path.parse(req.file.originalname).name;
const subFolder = `${timestamp}_${originalNameWithoutExt}`;
targetDir = path.join(targetDir, subFolder);
}
await fs.mkdir(targetDir, { recursive: true });
const targetFilePath = path.join(targetDir, req.file.filename);
@ -1149,7 +1164,7 @@ export async function handleUIApiRequests(method, pathParam, req, res, currentCo
if (method === 'POST' && pathParam === '/api/reload-config') {
try {
// 调用重载配置函数
const newConfig = await reloadConfig();
const newConfig = await reloadConfig(providerPoolManager);
// 广播更新事件
broadcastEvent('config_update', {
@ -1575,7 +1590,8 @@ async function scanOAuthDirectory(dirPath, usedPaths, currentConfig) {
} else if (file.isDirectory()) {
// 递归扫描子目录(限制深度)
const relativePath = path.relative(process.cwd(), fullPath);
if (relativePath.split(path.sep).length < 3) { // 最大深度3层
// 最大深度4层以支持 configs/kiro/{subfolder}/file.json 这样的结构
if (relativePath.split(path.sep).length < 4) {
const subFiles = await scanOAuthDirectory(fullPath, usedPaths, currentConfig);
oauthFiles.push(...subFiles);
}

View file

@ -67,10 +67,10 @@ function initEventListeners() {
});
// 提供商池配置监听
const providerPoolsInput = document.getElementById('providerPoolsFilePath');
if (providerPoolsInput) {
providerPoolsInput.addEventListener('input', handleProviderPoolsConfigChange);
}
// const providerPoolsInput = document.getElementById('providerPoolsFilePath');
// if (providerPoolsInput) {
// providerPoolsInput.addEventListener('input', handleProviderPoolsConfigChange);
// }
// 日志容器滚动
if (elements.logsContainer) {

View file

@ -623,8 +623,8 @@
</div>
<div class="form-group pool-section">
<label for="providerPoolsFilePath">提供商池配置文件路径</label>
<input type="text" id="providerPoolsFilePath" class="form-control" value="" placeholder="例如: provider_pools.json">
<label for="providerPoolsFilePath">提供商池配置文件路径(不能为空)</label>
<input type="text" id="providerPoolsFilePath" class="form-control" value="" placeholder="默认: provider_pools.json">
<small class="form-text">配置了提供商池后,默认使用提供商池的配置,提供商池配置失效降级到默认配置</small>
</div>