// ===================================================== // 連線生命週期管理器 // ===================================================== import { db } from './database'; import { dbFailover } from './database-failover'; export class ConnectionLifecycleManager { private static instance: ConnectionLifecycleManager; private activeConnections = new Map(); 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();