perf(api): 为所有API服务添加HTTP连接池配置防止资源泄漏
为Claude、OpenAI、Gemini、Qwen等API服务添加HTTP/HTTPS agent配置,设置keepAlive、maxSockets等参数以限制连接池大小,避免资源泄漏问题。同时统一了各服务的axios配置方式,提高网络请求的稳定性和性能。
This commit is contained in:
parent
b364341f67
commit
1c46bb547b
7 changed files with 149 additions and 11 deletions
|
|
@ -1,4 +1,6 @@
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import * as http from 'http';
|
||||||
|
import * as https from 'https';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Claude API Core Service Class.
|
* Claude API Core Service Class.
|
||||||
|
|
@ -27,8 +29,24 @@ export class ClaudeApiService {
|
||||||
* @returns {object} Axios instance.
|
* @returns {object} Axios instance.
|
||||||
*/
|
*/
|
||||||
createClient() {
|
createClient() {
|
||||||
|
// 配置 HTTP/HTTPS agent 限制连接池大小,避免资源泄漏
|
||||||
|
const httpAgent = new http.Agent({
|
||||||
|
keepAlive: true,
|
||||||
|
maxSockets: 100,
|
||||||
|
maxFreeSockets: 5,
|
||||||
|
timeout: 120000,
|
||||||
|
});
|
||||||
|
const httpsAgent = new https.Agent({
|
||||||
|
keepAlive: true,
|
||||||
|
maxSockets: 100,
|
||||||
|
maxFreeSockets: 5,
|
||||||
|
timeout: 120000,
|
||||||
|
});
|
||||||
|
|
||||||
const axiosConfig = {
|
const axiosConfig = {
|
||||||
baseURL: this.baseUrl,
|
baseURL: this.baseUrl,
|
||||||
|
httpAgent,
|
||||||
|
httpsAgent,
|
||||||
headers: {
|
headers: {
|
||||||
'x-api-key': this.apiKey,
|
'x-api-key': this.apiKey,
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
|
|
||||||
|
|
@ -308,15 +308,15 @@ export class KiroApiService {
|
||||||
// 配置 HTTP/HTTPS agent 限制连接池大小,避免资源泄漏
|
// 配置 HTTP/HTTPS agent 限制连接池大小,避免资源泄漏
|
||||||
const httpAgent = new http.Agent({
|
const httpAgent = new http.Agent({
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
maxSockets: 200, // 每个主机最多 10 个连接
|
maxSockets: 100, // 每个主机最多 10 个连接
|
||||||
maxFreeSockets: 5, // 最多保留 5 个空闲连接
|
maxFreeSockets: 5, // 最多保留 5 个空闲连接
|
||||||
timeout: 60000, // 空闲连接 60 秒后关闭
|
timeout: 120000, // 空闲连接 60 秒后关闭
|
||||||
});
|
});
|
||||||
const httpsAgent = new https.Agent({
|
const httpsAgent = new https.Agent({
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
maxSockets: 100,
|
maxSockets: 100,
|
||||||
maxFreeSockets: 5,
|
maxFreeSockets: 5,
|
||||||
timeout: 60000,
|
timeout: 120000,
|
||||||
});
|
});
|
||||||
|
|
||||||
const axiosConfig = {
|
const axiosConfig = {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { OAuth2Client } from 'google-auth-library';
|
import { OAuth2Client } from 'google-auth-library';
|
||||||
import * as http from 'http';
|
import * as http from 'http';
|
||||||
|
import * as https from 'https';
|
||||||
import { promises as fs } from 'fs';
|
import { promises as fs } from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
|
|
@ -9,6 +10,20 @@ import open from 'open';
|
||||||
import { API_ACTIONS, formatExpiryTime } from '../common.js';
|
import { API_ACTIONS, formatExpiryTime } from '../common.js';
|
||||||
import { getProviderModels } from '../provider-models.js';
|
import { getProviderModels } from '../provider-models.js';
|
||||||
|
|
||||||
|
// 配置 HTTP/HTTPS agent 限制连接池大小,避免资源泄漏
|
||||||
|
const httpAgent = new http.Agent({
|
||||||
|
keepAlive: true,
|
||||||
|
maxSockets: 100,
|
||||||
|
maxFreeSockets: 5,
|
||||||
|
timeout: 120000,
|
||||||
|
});
|
||||||
|
const httpsAgent = new https.Agent({
|
||||||
|
keepAlive: true,
|
||||||
|
maxSockets: 100,
|
||||||
|
maxFreeSockets: 5,
|
||||||
|
timeout: 120000,
|
||||||
|
});
|
||||||
|
|
||||||
// --- Constants ---
|
// --- Constants ---
|
||||||
const AUTH_REDIRECT_PORT = 8086;
|
const AUTH_REDIRECT_PORT = 8086;
|
||||||
const CREDENTIALS_DIR = '.antigravity';
|
const CREDENTIALS_DIR = '.antigravity';
|
||||||
|
|
@ -210,7 +225,14 @@ function ensureRolesInContents(requestBody) {
|
||||||
|
|
||||||
export class AntigravityApiService {
|
export class AntigravityApiService {
|
||||||
constructor(config) {
|
constructor(config) {
|
||||||
this.authClient = new OAuth2Client(OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET);
|
// 配置 OAuth2Client 使用自定义的 HTTP agent
|
||||||
|
this.authClient = new OAuth2Client({
|
||||||
|
clientId: OAUTH_CLIENT_ID,
|
||||||
|
clientSecret: OAUTH_CLIENT_SECRET,
|
||||||
|
transporterOptions: {
|
||||||
|
agent: httpsAgent,
|
||||||
|
},
|
||||||
|
});
|
||||||
this.availableModels = [];
|
this.availableModels = [];
|
||||||
this.isInitialized = false;
|
this.isInitialized = false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { OAuth2Client } from 'google-auth-library';
|
import { OAuth2Client } from 'google-auth-library';
|
||||||
import * as http from 'http';
|
import * as http from 'http';
|
||||||
|
import * as https from 'https';
|
||||||
import { promises as fs } from 'fs';
|
import { promises as fs } from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
|
|
@ -8,6 +9,20 @@ import open from 'open';
|
||||||
import { API_ACTIONS, formatExpiryTime } from '../common.js';
|
import { API_ACTIONS, formatExpiryTime } from '../common.js';
|
||||||
import { getProviderModels } from '../provider-models.js';
|
import { getProviderModels } from '../provider-models.js';
|
||||||
|
|
||||||
|
// 配置 HTTP/HTTPS agent 限制连接池大小,避免资源泄漏
|
||||||
|
const httpAgent = new http.Agent({
|
||||||
|
keepAlive: true,
|
||||||
|
maxSockets: 100,
|
||||||
|
maxFreeSockets: 5,
|
||||||
|
timeout: 120000,
|
||||||
|
});
|
||||||
|
const httpsAgent = new https.Agent({
|
||||||
|
keepAlive: true,
|
||||||
|
maxSockets: 100,
|
||||||
|
maxFreeSockets: 5,
|
||||||
|
timeout: 120000,
|
||||||
|
});
|
||||||
|
|
||||||
// --- Constants ---
|
// --- Constants ---
|
||||||
const AUTH_REDIRECT_PORT = 8085;
|
const AUTH_REDIRECT_PORT = 8085;
|
||||||
const CREDENTIALS_DIR = '.gemini';
|
const CREDENTIALS_DIR = '.gemini';
|
||||||
|
|
@ -177,7 +192,14 @@ async function* apply_anti_truncation_to_stream(service, model, requestBody) {
|
||||||
|
|
||||||
export class GeminiApiService {
|
export class GeminiApiService {
|
||||||
constructor(config) {
|
constructor(config) {
|
||||||
this.authClient = new OAuth2Client(OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET);
|
// 配置 OAuth2Client 使用自定义的 HTTP agent
|
||||||
|
this.authClient = new OAuth2Client({
|
||||||
|
clientId: OAUTH_CLIENT_ID,
|
||||||
|
clientSecret: OAUTH_CLIENT_SECRET,
|
||||||
|
transporterOptions: {
|
||||||
|
agent: httpsAgent,
|
||||||
|
},
|
||||||
|
});
|
||||||
this.availableModels = [];
|
this.availableModels = [];
|
||||||
this.isInitialized = false;
|
this.isInitialized = false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import * as http from 'http';
|
||||||
|
import * as https from 'https';
|
||||||
|
|
||||||
// Assumed OpenAI API specification service for interacting with third-party models
|
// Assumed OpenAI API specification service for interacting with third-party models
|
||||||
export class OpenAIApiService {
|
export class OpenAIApiService {
|
||||||
|
|
@ -12,8 +14,24 @@ export class OpenAIApiService {
|
||||||
this.useSystemProxy = config?.USE_SYSTEM_PROXY_OPENAI ?? false;
|
this.useSystemProxy = config?.USE_SYSTEM_PROXY_OPENAI ?? false;
|
||||||
console.log(`[OpenAI] System proxy ${this.useSystemProxy ? 'enabled' : 'disabled'}`);
|
console.log(`[OpenAI] System proxy ${this.useSystemProxy ? 'enabled' : 'disabled'}`);
|
||||||
|
|
||||||
|
// 配置 HTTP/HTTPS agent 限制连接池大小,避免资源泄漏
|
||||||
|
const httpAgent = new http.Agent({
|
||||||
|
keepAlive: true,
|
||||||
|
maxSockets: 100,
|
||||||
|
maxFreeSockets: 5,
|
||||||
|
timeout: 120000,
|
||||||
|
});
|
||||||
|
const httpsAgent = new https.Agent({
|
||||||
|
keepAlive: true,
|
||||||
|
maxSockets: 100,
|
||||||
|
maxFreeSockets: 5,
|
||||||
|
timeout: 120000,
|
||||||
|
});
|
||||||
|
|
||||||
const axiosConfig = {
|
const axiosConfig = {
|
||||||
baseURL: this.baseUrl,
|
baseURL: this.baseUrl,
|
||||||
|
httpAgent,
|
||||||
|
httpsAgent,
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Authorization': `Bearer ${this.apiKey}`
|
'Authorization': `Bearer ${this.apiKey}`
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import * as http from 'http';
|
||||||
|
import * as https from 'https';
|
||||||
|
|
||||||
// OpenAI Responses API specification service for interacting with third-party models
|
// OpenAI Responses API specification service for interacting with third-party models
|
||||||
export class OpenAIResponsesApiService {
|
export class OpenAIResponsesApiService {
|
||||||
|
|
@ -9,14 +11,39 @@ export class OpenAIResponsesApiService {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.apiKey = config.OPENAI_API_KEY;
|
this.apiKey = config.OPENAI_API_KEY;
|
||||||
this.baseUrl = config.OPENAI_BASE_URL || 'https://api.openai.com/v1';
|
this.baseUrl = config.OPENAI_BASE_URL || 'https://api.openai.com/v1';
|
||||||
// console.log(`[OpenAIResponsesApiService] Base URL: ${JSON.stringify(config)}`);
|
this.useSystemProxy = config?.USE_SYSTEM_PROXY_OPENAI ?? false;
|
||||||
this.axiosInstance = axios.create({
|
console.log(`[OpenAIResponses] System proxy ${this.useSystemProxy ? 'enabled' : 'disabled'}`);
|
||||||
|
|
||||||
|
// 配置 HTTP/HTTPS agent 限制连接池大小,避免资源泄漏
|
||||||
|
const httpAgent = new http.Agent({
|
||||||
|
keepAlive: true,
|
||||||
|
maxSockets: 100,
|
||||||
|
maxFreeSockets: 5,
|
||||||
|
timeout: 120000,
|
||||||
|
});
|
||||||
|
const httpsAgent = new https.Agent({
|
||||||
|
keepAlive: true,
|
||||||
|
maxSockets: 100,
|
||||||
|
maxFreeSockets: 5,
|
||||||
|
timeout: 120000,
|
||||||
|
});
|
||||||
|
|
||||||
|
const axiosConfig = {
|
||||||
baseURL: this.baseUrl,
|
baseURL: this.baseUrl,
|
||||||
|
httpAgent,
|
||||||
|
httpsAgent,
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Authorization': `Bearer ${this.apiKey}`
|
'Authorization': `Bearer ${this.apiKey}`
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
// 禁用系统代理以避免HTTPS代理错误
|
||||||
|
if (!this.useSystemProxy) {
|
||||||
|
axiosConfig.proxy = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.axiosInstance = axios.create(axiosConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
async callApi(endpoint, body, isRetry = false, retryCount = 0) {
|
async callApi(endpoint, body, isRetry = false, retryCount = 0) {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ import crypto from 'crypto';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { promises as fs, unlinkSync } from 'node:fs';
|
import { promises as fs, unlinkSync } from 'node:fs';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
|
import * as http from 'http';
|
||||||
|
import * as https from 'https';
|
||||||
import open from 'open';
|
import open from 'open';
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import { randomUUID } from 'node:crypto';
|
import { randomUUID } from 'node:crypto';
|
||||||
|
|
@ -187,13 +189,28 @@ export class QwenApiService {
|
||||||
console.log('[Qwen] Initializing Qwen API Service...');
|
console.log('[Qwen] Initializing Qwen API Service...');
|
||||||
await this._initializeAuth();
|
await this._initializeAuth();
|
||||||
|
|
||||||
|
// 配置 HTTP/HTTPS agent 限制连接池大小,避免资源泄漏
|
||||||
|
const httpAgent = new http.Agent({
|
||||||
|
keepAlive: true,
|
||||||
|
maxSockets: 100,
|
||||||
|
maxFreeSockets: 5,
|
||||||
|
timeout: 120000,
|
||||||
|
});
|
||||||
|
const httpsAgent = new https.Agent({
|
||||||
|
keepAlive: true,
|
||||||
|
maxSockets: 100,
|
||||||
|
maxFreeSockets: 5,
|
||||||
|
timeout: 120000,
|
||||||
|
});
|
||||||
|
|
||||||
const axiosConfig = {
|
const axiosConfig = {
|
||||||
baseURL: DEFAULT_QWEN_BASE_URL,
|
baseURL: DEFAULT_QWEN_BASE_URL,
|
||||||
|
httpAgent,
|
||||||
|
httpsAgent,
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Authorization': `Bearer `,
|
'Authorization': `Bearer `,
|
||||||
},
|
},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 禁用系统代理
|
// 禁用系统代理
|
||||||
|
|
@ -501,8 +518,24 @@ export class QwenApiService {
|
||||||
try {
|
try {
|
||||||
const { token, endpoint: qwenBaseUrl } = await this.getValidToken();
|
const { token, endpoint: qwenBaseUrl } = await this.getValidToken();
|
||||||
|
|
||||||
|
// 配置 HTTP/HTTPS agent 限制连接池大小,避免资源泄漏
|
||||||
|
const httpAgent = new http.Agent({
|
||||||
|
keepAlive: true,
|
||||||
|
maxSockets: 100,
|
||||||
|
maxFreeSockets: 5,
|
||||||
|
timeout: 120000,
|
||||||
|
});
|
||||||
|
const httpsAgent = new https.Agent({
|
||||||
|
keepAlive: true,
|
||||||
|
maxSockets: 100,
|
||||||
|
maxFreeSockets: 5,
|
||||||
|
timeout: 120000,
|
||||||
|
});
|
||||||
|
|
||||||
const axiosConfig = {
|
const axiosConfig = {
|
||||||
baseURL: qwenBaseUrl,
|
baseURL: qwenBaseUrl,
|
||||||
|
httpAgent,
|
||||||
|
httpsAgent,
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Authorization': `Bearer ${token}`,
|
'Authorization': `Bearer ${token}`,
|
||||||
|
|
@ -510,8 +543,6 @@ export class QwenApiService {
|
||||||
'X-DashScope-UserAgent': userAgent,
|
'X-DashScope-UserAgent': userAgent,
|
||||||
'X-DashScope-AuthType': 'qwen-oauth',
|
'X-DashScope-AuthType': 'qwen-oauth',
|
||||||
},
|
},
|
||||||
// 添加 HTTPS 代理修复相关配置
|
|
||||||
httpsAgent: undefined, // axios-https-proxy-fix 会自动处理
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 禁用系统代理
|
// 禁用系统代理
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue