修復 too many connection 問題

This commit is contained in:
2025-09-21 02:46:16 +08:00
parent a36ab3c98d
commit 808d5bb52c
36 changed files with 5582 additions and 249 deletions

View File

@@ -0,0 +1,178 @@
// =====================================================
// 連線生命週期管理器
// =====================================================
import { db } from './database';
import { dbFailover } from './database-failover';
export class ConnectionLifecycleManager {
private static instance: ConnectionLifecycleManager;
private activeConnections = new Map<string, {
connection: any;
createdAt: number;
lastUsed: number;
userId?: string;
sessionId?: string;
}>();
private cleanupInterval: NodeJS.Timeout | null = null;
private maxIdleTime = 5 * 60 * 1000; // 5分鐘空閒超時
private maxConnectionAge = 30 * 60 * 1000; // 30分鐘最大連線時間
private constructor() {
this.startCleanupProcess();
}
public static getInstance(): ConnectionLifecycleManager {
if (!ConnectionLifecycleManager.instance) {
ConnectionLifecycleManager.instance = new ConnectionLifecycleManager();
}
return ConnectionLifecycleManager.instance;
}
// 註冊連線
public registerConnection(connectionId: string, connection: any, metadata?: {
userId?: string;
sessionId?: string;
}) {
this.activeConnections.set(connectionId, {
connection,
createdAt: Date.now(),
lastUsed: Date.now(),
userId: metadata?.userId,
sessionId: metadata?.sessionId
});
console.log(`📝 註冊連線: ${connectionId} (總數: ${this.activeConnections.size})`);
}
// 更新連線使用時間
public updateConnectionUsage(connectionId: string) {
const conn = this.activeConnections.get(connectionId);
if (conn) {
conn.lastUsed = Date.now();
}
}
// 釋放連線
public releaseConnection(connectionId: string) {
const conn = this.activeConnections.get(connectionId);
if (conn) {
try {
if (conn.connection && typeof conn.connection.release === 'function') {
conn.connection.release();
}
this.activeConnections.delete(connectionId);
console.log(`🗑️ 釋放連線: ${connectionId} (剩餘: ${this.activeConnections.size})`);
} catch (error) {
console.error(`❌ 釋放連線失敗: ${connectionId}`, error);
}
}
}
// 開始清理程序
private startCleanupProcess() {
// 每30秒檢查一次空閒連線
this.cleanupInterval = setInterval(() => {
this.cleanupIdleConnections();
}, 30 * 1000);
console.log('🧹 連線生命週期管理器已啟動');
}
// 清理空閒連線
private cleanupIdleConnections() {
const now = Date.now();
const toRemove: string[] = [];
for (const [connectionId, conn] of this.activeConnections) {
const idleTime = now - conn.lastUsed;
const connectionAge = now - conn.createdAt;
// 檢查空閒時間
if (idleTime > this.maxIdleTime) {
console.log(`⏰ 連線 ${connectionId} 空閒時間過長 (${Math.round(idleTime / 1000)}s),準備釋放`);
toRemove.push(connectionId);
}
// 檢查連線年齡
else if (connectionAge > this.maxConnectionAge) {
console.log(`⏰ 連線 ${connectionId} 存在時間過長 (${Math.round(connectionAge / 1000)}s),準備釋放`);
toRemove.push(connectionId);
}
}
// 釋放需要清理的連線
toRemove.forEach(connectionId => {
this.releaseConnection(connectionId);
});
if (toRemove.length > 0) {
console.log(`🧹 清理了 ${toRemove.length} 個空閒連線`);
}
}
// 強制清理所有連線
public forceCleanupAll() {
console.log('🚨 強制清理所有連線...');
const connectionIds = Array.from(this.activeConnections.keys());
connectionIds.forEach(connectionId => {
this.releaseConnection(connectionId);
});
console.log(`✅ 已清理 ${connectionIds.length} 個連線`);
}
// 獲取連線統計
public getConnectionStats() {
const now = Date.now();
const connections = Array.from(this.activeConnections.values());
const idleConnections = connections.filter(conn =>
now - conn.lastUsed > this.maxIdleTime
).length;
const oldConnections = connections.filter(conn =>
now - conn.createdAt > this.maxConnectionAge
).length;
return {
totalConnections: this.activeConnections.size,
idleConnections,
oldConnections,
maxIdleTime: this.maxIdleTime,
maxConnectionAge: this.maxConnectionAge,
connections: connections.map(conn => ({
createdAt: new Date(conn.createdAt).toISOString(),
lastUsed: new Date(conn.lastUsed).toISOString(),
idleTime: now - conn.lastUsed,
age: now - conn.createdAt,
userId: conn.userId,
sessionId: conn.sessionId
}))
};
}
// 停止清理程序
public stop() {
if (this.cleanupInterval) {
clearInterval(this.cleanupInterval);
this.cleanupInterval = null;
}
// 清理所有連線
this.forceCleanupAll();
console.log('⏹️ 連線生命週期管理器已停止');
}
// 設置清理參數
public setCleanupParams(maxIdleTime?: number, maxConnectionAge?: number) {
if (maxIdleTime) this.maxIdleTime = maxIdleTime;
if (maxConnectionAge) this.maxConnectionAge = maxConnectionAge;
console.log(`⚙️ 更新清理參數: 空閒時間=${this.maxIdleTime}ms, 最大年齡=${this.maxConnectionAge}ms`);
}
}
// 導出單例實例
export const connectionLifecycleManager = ConnectionLifecycleManager.getInstance();