// ===================================================== // 緊急連線清理工具 // ===================================================== import { db } from './database'; import { dbFailover } from './database-failover'; import { dbMonitor } from './database-monitor'; export class EmergencyConnectionCleanup { private static instance: EmergencyConnectionCleanup; private constructor() {} public static getInstance(): EmergencyConnectionCleanup { if (!EmergencyConnectionCleanup.instance) { EmergencyConnectionCleanup.instance = new EmergencyConnectionCleanup(); } return EmergencyConnectionCleanup.instance; } // 立即停止所有監控和清理所有連線 public async emergencyCleanup() { console.log('🚨 執行緊急連線清理...'); try { // 1. 立即停止所有監控 console.log('⏹️ 停止資料庫監控...'); dbMonitor.stopMonitoring(); // 2. 強制關閉所有連線池 console.log('🔌 關閉主要資料庫連線池...'); await db.close(); console.log('🔌 關閉備援資料庫連線池...'); await dbFailover.close(); // 3. 等待一段時間讓連線完全關閉 console.log('⏳ 等待連線關閉...'); await new Promise(resolve => setTimeout(resolve, 2000)); // 4. 檢查連線狀態 await this.checkConnectionStatus(); console.log('✅ 緊急清理完成'); } catch (error) { console.error('❌ 緊急清理失敗:', error); } } // 檢查連線狀態(不建立新連線) private async checkConnectionStatus() { try { // 使用一個臨時連線來檢查狀態 const tempConnection = await db.getConnection(); try { const [statusResult] = await tempConnection.execute(` SHOW STATUS LIKE 'Threads_connected' `); const [maxConnResult] = await tempConnection.execute(` SHOW VARIABLES LIKE 'max_connections' `); const currentConnections = statusResult[0]?.Value || 0; const maxConnections = maxConnResult[0]?.Value || 100; const usagePercentage = (currentConnections / maxConnections) * 100; console.log(`📊 清理後連線狀態: ${currentConnections}/${maxConnections} (${usagePercentage.toFixed(1)}%)`); if (currentConnections > 5) { console.warn(`⚠️ 仍有 ${currentConnections} 個連線未關閉`); } else { console.log('✅ 連線已成功清理'); } } finally { tempConnection.release(); } } catch (error) { console.error('❌ 檢查連線狀態失敗:', error); } } // 強制殺死所有資料庫連線 public async forceKillAllConnections() { console.log('💀 強制殺死所有資料庫連線...'); try { const tempConnection = await db.getConnection(); try { // 獲取所有連線ID const [connections] = await tempConnection.execute(` SELECT ID FROM information_schema.PROCESSLIST WHERE USER = ? AND COMMAND != 'Sleep' `, [process.env.DB_USER || 'A999']); console.log(`🔍 找到 ${connections.length} 個活躍連線`); // 殺死所有連線(除了當前連線) for (const conn of connections) { if (conn.ID !== tempConnection.threadId) { try { await tempConnection.execute(`KILL ${conn.ID}`); console.log(`💀 已殺死連線 ${conn.ID}`); } catch (error) { console.log(`⚠️ 無法殺死連線 ${conn.ID}:`, error.message); } } } // 等待連線關閉 await new Promise(resolve => setTimeout(resolve, 1000)); // 再次檢查狀態 await this.checkConnectionStatus(); } finally { tempConnection.release(); } } catch (error) { console.error('❌ 強制殺死連線失敗:', error); } } // 獲取連線詳情 public async getConnectionDetails() { try { const tempConnection = await db.getConnection(); try { const [connections] = await tempConnection.execute(` SELECT ID, USER, HOST, DB, COMMAND, TIME, STATE, INFO FROM information_schema.PROCESSLIST WHERE USER = ? ORDER BY TIME DESC `, [process.env.DB_USER || 'A999']); console.log('📋 當前資料庫連線詳情:'); connections.forEach((conn, index) => { console.log(`${index + 1}. ID: ${conn.ID}, 用戶: ${conn.USER}, 時間: ${conn.TIME}s, 狀態: ${conn.STATE}`); if (conn.INFO && conn.INFO.length > 50) { console.log(` 查詢: ${conn.INFO.substring(0, 50)}...`); } else if (conn.INFO) { console.log(` 查詢: ${conn.INFO}`); } }); return connections; } finally { tempConnection.release(); } } catch (error) { console.error('❌ 獲取連線詳情失敗:', error); return []; } } } // 導出單例實例 export const emergencyCleanup = EmergencyConnectionCleanup.getInstance();