feat(provider): 添加初始化健康检查时重置使用计数功能
在初始化健康检查时重置provider的使用计数,确保初始化时状态完全重置 同时优化请求处理逻辑,提前处理OPTIONS和健康检查请求
This commit is contained in:
parent
f0201a484e
commit
484d71fcd3
2 changed files with 45 additions and 41 deletions
|
|
@ -450,7 +450,7 @@ async function initApiService(config) {
|
|||
providerPoolManager = new ProviderPoolManager(config.providerPools, { globalConfig: config });
|
||||
console.log('[Initialization] ProviderPoolManager initialized with configured pools.');
|
||||
// 可以选择在这里触发一次健康检查
|
||||
providerPoolManager.performHealthChecks();
|
||||
providerPoolManager.performHealthChecks(true);
|
||||
} else {
|
||||
console.log('[Initialization] No provider pools configured. Using single provider mode.');
|
||||
}
|
||||
|
|
@ -555,10 +555,45 @@ function createRequestHandler(config) {
|
|||
return async function requestHandler(req, res) {
|
||||
// Deep copy the config for each request to allow dynamic modification
|
||||
const currentConfig = deepmerge({}, config);
|
||||
|
||||
console.log(`\n${new Date().toLocaleString()}`);
|
||||
console.log(`[Server] Received request: ${req.method} http://${req.headers.host}${req.url}`);
|
||||
|
||||
const requestUrl = new URL(req.url, `http://${req.headers.host}`);
|
||||
let path = requestUrl.pathname;
|
||||
|
||||
const method = req.method;
|
||||
if (method === 'OPTIONS') {
|
||||
// 设置 CORS 头部,允许所有来源和方法
|
||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
|
||||
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, x-goog-api-key, Model-Provider'); // 添加 Model-Provider
|
||||
|
||||
// OPTIONS 请求通常返回 204 No Content
|
||||
res.writeHead(204);
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
// Health check endpoint - no authentication required
|
||||
if (method === 'GET' && path === '/health') {
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||
return res.end(JSON.stringify({
|
||||
status: 'healthy',
|
||||
timestamp: new Date().toISOString(),
|
||||
provider: currentConfig.MODEL_PROVIDER
|
||||
}));
|
||||
}
|
||||
|
||||
// Ignore count_tokens requests
|
||||
if (path.includes('/count_tokens')) {
|
||||
console.log(`[Server] Ignoring count_tokens request: ${path}`);
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||
return res.end(JSON.stringify({
|
||||
tokens: 0,
|
||||
message: 'Token counting is not supported'
|
||||
}));
|
||||
}
|
||||
|
||||
// Allow overriding MODEL_PROVIDER via request header
|
||||
const modelProviderHeader = req.headers['model-provider'];
|
||||
if (modelProviderHeader) {
|
||||
|
|
@ -566,9 +601,7 @@ function createRequestHandler(config) {
|
|||
console.log(`[Config] MODEL_PROVIDER overridden by header to: ${currentConfig.MODEL_PROVIDER}`);
|
||||
//delete req.headers['model-provider']; // 保持不变,以便后端可以继续处理原始头
|
||||
}
|
||||
|
||||
const requestUrl = new URL(req.url, `http://${req.headers.host}`);
|
||||
let path = requestUrl.pathname;
|
||||
|
||||
// Check if the first path segment matches a MODEL_PROVIDER and switch if it does
|
||||
const pathSegments = path.split('/').filter(segment => segment.length > 0);
|
||||
if (pathSegments.length > 0) {
|
||||
|
|
@ -605,39 +638,6 @@ function createRequestHandler(config) {
|
|||
return;
|
||||
}
|
||||
|
||||
const method = req.method;
|
||||
if (method === 'OPTIONS') {
|
||||
// 设置 CORS 头部,允许所有来源和方法
|
||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
|
||||
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, x-goog-api-key, Model-Provider'); // 添加 Model-Provider
|
||||
|
||||
// OPTIONS 请求通常返回 204 No Content
|
||||
res.writeHead(204);
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
// Health check endpoint - no authentication required
|
||||
if (method === 'GET' && path === '/health') {
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||
return res.end(JSON.stringify({
|
||||
status: 'healthy',
|
||||
timestamp: new Date().toISOString(),
|
||||
provider: currentConfig.MODEL_PROVIDER
|
||||
}));
|
||||
}
|
||||
|
||||
// Ignore count_tokens requests
|
||||
if (path.includes('/count_tokens')) {
|
||||
console.log(`[Server] Ignoring count_tokens request: ${path}`);
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||
return res.end(JSON.stringify({
|
||||
tokens: 0,
|
||||
message: 'Token counting is not supported'
|
||||
}));
|
||||
}
|
||||
|
||||
if (!isAuthorized(req, requestUrl, currentConfig.REQUIRED_API_KEY)) {
|
||||
res.writeHead(401, { 'Content-Type': 'application/json' });
|
||||
return res.end(JSON.stringify({ error: { message: 'Unauthorized: API key is invalid or missing.' } }));
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ export class ProviderPoolManager {
|
|||
* @param {string} providerType - The type of the provider.
|
||||
* @param {object} providerConfig - The configuration of the provider to mark.
|
||||
*/
|
||||
markProviderHealthy(providerType, providerConfig) {
|
||||
markProviderHealthy(isInit, providerType, providerConfig) {
|
||||
const pool = this.providerStatus[providerType];
|
||||
if (pool) {
|
||||
const provider = pool.find(p => p.uuid === providerConfig.uuid);
|
||||
|
|
@ -125,6 +125,9 @@ export class ProviderPoolManager {
|
|||
provider.config.isHealthy = true;
|
||||
provider.config.errorCount = 0; // Reset error count on health recovery
|
||||
provider.config.lastErrorTime = null; // Reset lastErrorTime when healthy
|
||||
if (isInit) {
|
||||
provider.config.usageCount = 0; // Reset usage count on health recovery
|
||||
}
|
||||
console.log(`[ProviderPoolManager] Marked provider as healthy: ${JSON.stringify(providerConfig)} for type ${providerType}`);
|
||||
|
||||
// 优化1: 使用防抖保存
|
||||
|
|
@ -137,7 +140,7 @@ export class ProviderPoolManager {
|
|||
* Performs health checks on all providers in the pool.
|
||||
* This method would typically be called periodically (e.g., via cron job).
|
||||
*/
|
||||
async performHealthChecks() {
|
||||
async performHealthChecks(isInit = false) {
|
||||
console.log('[ProviderPoolManager] Performing health checks on all providers...');
|
||||
const now = new Date();
|
||||
for (const providerType in this.providerStatus) {
|
||||
|
|
@ -158,10 +161,11 @@ export class ProviderPoolManager {
|
|||
if (isHealthy) {
|
||||
if (!providerStatus.config.isHealthy) {
|
||||
// Provider was unhealthy but is now healthy
|
||||
this.markProviderHealthy(providerType, providerConfig);
|
||||
this.markProviderHealthy(isInit, providerType, providerConfig);
|
||||
console.log(`[ProviderPoolManager] Health check for ${JSON.stringify(providerConfig)} (${providerType}): Marked Healthy (actual check)`);
|
||||
} else {
|
||||
// Provider was already healthy and still is
|
||||
this.markProviderHealthy(isInit, providerType, providerConfig);
|
||||
console.log(`[ProviderPoolManager] Health check for ${JSON.stringify(providerConfig)} (${providerType}): Still Healthy`);
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Reference in a new issue