清理不必要的測試檔案

This commit is contained in:
2025-09-21 03:23:26 +08:00
parent 8b3af6608e
commit f6abef38e9
58 changed files with 1 additions and 8621 deletions

View File

@@ -4,7 +4,6 @@
import { dbShutdownManager } from './database-shutdown-manager';
import { startConnectionMonitoring } from './database-middleware';
import { smartPool } from './smart-connection-pool';
// 應用程式初始化
export function initializeApp() {
@@ -20,11 +19,6 @@ export function initializeApp() {
console.log('📊 啟動資料庫連線監控...');
startConnectionMonitoring();
// 初始化智能連線池
console.log('🧠 初始化智能連線池...');
const poolStats = smartPool.getConnectionStats();
console.log('✅ 智能連線池已初始化:', poolStats);
console.log('✅ 應用程式初始化完成');
} catch (error) {

View File

@@ -1,231 +0,0 @@
// =====================================================
// 客戶端連線清理腳本
// =====================================================
export class ClientConnectionCleanup {
private static instance: ClientConnectionCleanup;
private isCleaning = false;
private clientId: string;
private constructor() {
this.clientId = this.generateClientId();
this.setupEventListeners();
}
public static getInstance(): ClientConnectionCleanup {
if (!ClientConnectionCleanup.instance) {
ClientConnectionCleanup.instance = new ClientConnectionCleanup();
}
return ClientConnectionCleanup.instance;
}
// 生成客戶端唯一標識符
private generateClientId(): string {
const timestamp = Date.now();
const random = Math.random().toString(36).substring(2);
return `client_${timestamp}_${random}`;
}
// 設置事件監聽器
private setupEventListeners() {
// 確保在瀏覽器環境中執行
if (typeof window === 'undefined') {
console.log('🖥️ 客戶端連線清理跳過(服務端環境)');
return;
}
// 頁面關閉前清理
window.addEventListener('beforeunload', () => {
this.cleanupOnUnload();
});
// 頁面隱藏時清理
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
this.cleanupOnHidden();
}
});
// 頁面卸載時清理
window.addEventListener('unload', () => {
this.cleanupOnUnload();
});
// 定期清理每5分鐘
setInterval(() => {
this.periodicCleanup();
}, 5 * 60 * 1000);
console.log('🖥️ 客戶端連線清理已啟動');
}
// 頁面關閉前清理
private async cleanupOnUnload() {
if (this.isCleaning) return;
// 確保在瀏覽器環境中執行
if (typeof window === 'undefined') return;
this.isCleaning = true;
console.log('🔄 頁面關閉前清理連線...');
try {
// 使用 sendBeacon 確保請求能夠發送
const data = JSON.stringify({
action: 'cleanup-current',
clientId: this.clientId,
timestamp: Date.now()
});
// 嘗試使用 sendBeacon
if (navigator.sendBeacon) {
navigator.sendBeacon('/api/ip-cleanup', data);
console.log('✅ 使用 sendBeacon 發送清理請求');
} else {
// 備用方案:使用 fetch
await fetch('/api/ip-cleanup', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: data,
keepalive: true
});
console.log('✅ 使用 fetch 發送清理請求');
}
} catch (error) {
console.error('❌ 清理請求發送失敗:', error);
}
}
// 頁面隱藏時清理
private async cleanupOnHidden() {
// 確保在瀏覽器環境中執行
if (typeof window === 'undefined') return;
console.log('🔄 頁面隱藏時清理連線...');
try {
await fetch('/api/ip-cleanup', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
action: 'cleanup-current',
clientId: this.clientId,
reason: 'page-hidden'
})
});
console.log('✅ 頁面隱藏清理完成');
} catch (error) {
console.error('❌ 頁面隱藏清理失敗:', error);
}
}
// 定期清理
private async periodicCleanup() {
// 確保在瀏覽器環境中執行
if (typeof window === 'undefined') return;
console.log('🔄 定期清理連線...');
try {
const response = await fetch('/api/ip-cleanup?action=local-stats');
const data = await response.json();
if (data.success && data.data.trackedConnections > 10) {
// 如果追蹤的連線數超過10個執行清理
await fetch('/api/ip-cleanup', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
action: 'cleanup-local',
clientId: this.clientId,
reason: 'periodic-cleanup'
})
});
console.log('✅ 定期清理完成');
}
} catch (error) {
console.error('❌ 定期清理失敗:', error);
}
}
// 手動清理
public async manualCleanup(): Promise<boolean> {
// 確保在瀏覽器環境中執行
if (typeof window === 'undefined') return false;
try {
const response = await fetch('/api/ip-cleanup', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
action: 'cleanup-current',
clientId: this.clientId,
reason: 'manual-cleanup'
})
});
const data = await response.json();
if (data.success) {
console.log('✅ 手動清理完成:', data.message);
return true;
} else {
console.error('❌ 手動清理失敗:', data.error);
return false;
}
} catch (error) {
console.error('❌ 手動清理錯誤:', error);
return false;
}
}
// 獲取連線狀態
public async getConnectionStatus() {
// 確保在瀏覽器環境中執行
if (typeof window === 'undefined') return null;
try {
const response = await fetch('/api/ip-cleanup?action=status');
const data = await response.json();
if (data.success) {
console.log('📊 連線狀態:', data.data);
return data.data;
} else {
console.error('❌ 獲取連線狀態失敗:', data.error);
return null;
}
} catch (error) {
console.error('❌ 獲取連線狀態錯誤:', error);
return null;
}
}
// 獲取客戶端 ID
public getClientId(): string {
return this.clientId;
}
}
// 導出單例實例
export const clientCleanup = ClientConnectionCleanup.getInstance();
// 在模組載入時自動初始化(只在瀏覽器環境中)
if (typeof window !== 'undefined') {
// 延遲初始化,確保 DOM 已載入
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
clientCleanup;
});
} else {
clientCleanup;
}
}

View File

@@ -1,178 +0,0 @@
// =====================================================
// 連線生命週期管理器
// =====================================================
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();

View File

@@ -5,7 +5,6 @@
import { db } from './database';
import { dbFailover } from './database-failover';
import { dbMonitor } from './database-monitor';
import { smartPool } from './smart-connection-pool';
export class DatabaseShutdownManager {
private static instance: DatabaseShutdownManager;
@@ -58,16 +57,6 @@ export class DatabaseShutdownManager {
}
});
// 添加智能連線池關閉處理器
this.addShutdownHandler('smart-pool', async () => {
console.log('🔄 正在清理智能連線池...');
try {
smartPool.forceCleanup();
console.log('✅ 智能連線池已清理');
} catch (error) {
console.error('❌ 清理智能連線池時發生錯誤:', error);
}
});
// 註冊系統信號處理器
this.registerSystemHandlers();

View File

@@ -1,175 +0,0 @@
// =====================================================
// 緊急連線清理工具
// =====================================================
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();

View File

@@ -1,251 +0,0 @@
// =====================================================
// 基於 IP 的連線管理器
// =====================================================
import mysql from 'mysql2/promise';
import { db } from './database';
export class IPBasedConnectionManager {
private static instance: IPBasedConnectionManager;
private clientIP: string | null = null;
private connectionTracker = new Map<string, {
connectionId: string;
createdAt: number;
lastUsed: number;
userAgent?: string;
}>();
private constructor() {
this.detectClientIP();
}
public static getInstance(): IPBasedConnectionManager {
if (!IPBasedConnectionManager.instance) {
IPBasedConnectionManager.instance = new IPBasedConnectionManager();
}
return IPBasedConnectionManager.instance;
}
// 檢測客戶端 IP
private detectClientIP() {
// 在瀏覽器環境中,我們無法直接獲取真實 IP
// 但我們可以通過其他方式來識別連線
if (typeof window !== 'undefined') {
// 客戶端:生成一個唯一標識符
this.clientIP = this.generateClientId();
console.log('🖥️ 客戶端標識符:', this.clientIP);
} else {
// 服務端:嘗試從環境變數或請求中獲取
this.clientIP = process.env.CLIENT_IP || 'server-side';
console.log('🖥️ 服務端標識符:', this.clientIP);
}
}
// 生成客戶端唯一標識符
private generateClientId(): string {
const timestamp = Date.now();
const random = Math.random().toString(36).substring(2);
return `client_${timestamp}_${random}`;
}
// 設置客戶端 IP從請求中獲取
public setClientIP(ip: string) {
this.clientIP = ip;
console.log('🖥️ 設置客戶端 IP:', ip);
}
// 獲取客戶端 IP
public getClientIP(): string | null {
return this.clientIP;
}
// 註冊連線(帶 IP 標識)
public registerConnection(connectionId: string, metadata?: {
userAgent?: string;
requestId?: string;
}) {
if (!this.clientIP) return;
this.connectionTracker.set(connectionId, {
connectionId,
createdAt: Date.now(),
lastUsed: Date.now(),
userAgent: metadata?.userAgent,
});
console.log(`📝 註冊連線: ${connectionId} (IP: ${this.clientIP})`);
}
// 更新連線使用時間
public updateConnectionUsage(connectionId: string) {
const conn = this.connectionTracker.get(connectionId);
if (conn) {
conn.lastUsed = Date.now();
}
}
// 釋放連線
public releaseConnection(connectionId: string) {
const conn = this.connectionTracker.get(connectionId);
if (conn) {
this.connectionTracker.delete(connectionId);
console.log(`🗑️ 釋放連線: ${connectionId} (IP: ${this.clientIP})`);
}
}
// 根據 IP 清理連線
public async cleanupConnectionsByIP(targetIP?: string): Promise<{
success: boolean;
killedCount: number;
message: string;
}> {
const ipToClean = targetIP || this.clientIP;
if (!ipToClean) {
return {
success: false,
killedCount: 0,
message: '無法識別客戶端 IP'
};
}
console.log(`🧹 開始清理 IP ${ipToClean} 的連線...`);
let connection = null;
let killedCount = 0;
try {
// 建立臨時連線
connection = await db.getConnection();
// 獲取指定 IP 的所有連線(使用更寬鬆的匹配)
const [connections] = await connection.execute(`
SELECT ID, USER, HOST, DB, COMMAND, TIME, STATE, INFO
FROM information_schema.PROCESSLIST
WHERE USER = ? AND (HOST LIKE ? OR HOST LIKE ? OR HOST LIKE ?)
ORDER BY TIME DESC
`, [
process.env.DB_USER || 'A999',
`%${ipToClean}%`, // 包含 IP 的 HOST
`%${ipToClean}.%`, // IP 開頭的 HOST
`%${ipToClean}-%` // IP 帶連字符的 HOST
]);
console.log(`🔍 找到 ${connections.length} 個來自 ${ipToClean} 的連線`);
// 顯示連線詳情
connections.forEach((conn: any, index: number) => {
console.log(`${index + 1}. ID: ${conn.ID}, HOST: ${conn.HOST}, 時間: ${conn.TIME}s, 狀態: ${conn.STATE}`);
});
// 殺死指定 IP 的連線(除了當前連線)
for (const conn of connections) {
if (conn.ID !== connection.threadId) {
try {
await connection.execute(`KILL ${conn.ID}`);
console.log(`💀 已殺死連線 ${conn.ID} (HOST: ${conn.HOST})`);
killedCount++;
} catch (error: any) {
console.log(`⚠️ 無法殺死連線 ${conn.ID}: ${error.message}`);
}
}
}
// 清理本地追蹤的連線
this.connectionTracker.clear();
console.log(`✅ 已清理 ${killedCount} 個來自 ${ipToClean} 的連線`);
return {
success: true,
killedCount,
message: `已清理 ${killedCount} 個來自 ${ipToClean} 的連線`
};
} catch (error) {
console.error('❌ 清理連線失敗:', error);
return {
success: false,
killedCount: 0,
message: `清理失敗: ${error instanceof Error ? error.message : '未知錯誤'}`
};
} finally {
if (connection) {
connection.release();
}
}
}
// 獲取指定 IP 的連線狀態
public async getConnectionsByIP(targetIP?: string): Promise<{
ip: string;
connectionCount: number;
connections: any[];
}> {
const ipToCheck = targetIP || this.clientIP;
if (!ipToCheck) {
return {
ip: 'unknown',
connectionCount: 0,
connections: []
};
}
let connection = null;
try {
connection = await db.getConnection();
const [connections] = await connection.execute(`
SELECT ID, USER, HOST, DB, COMMAND, TIME, STATE, INFO
FROM information_schema.PROCESSLIST
WHERE USER = ? AND HOST LIKE ?
ORDER BY TIME DESC
`, [process.env.DB_USER || 'A999', `%${ipToCheck}%`]);
return {
ip: ipToCheck,
connectionCount: connections.length,
connections: connections
};
} catch (error) {
console.error('❌ 獲取連線狀態失敗:', error);
return {
ip: ipToCheck,
connectionCount: 0,
connections: []
};
} finally {
if (connection) {
connection.release();
}
}
}
// 清理所有本地追蹤的連線
public cleanupLocalConnections() {
const count = this.connectionTracker.size;
this.connectionTracker.clear();
console.log(`🧹 已清理 ${count} 個本地追蹤的連線`);
return count;
}
// 獲取本地連線統計
public getLocalConnectionStats() {
return {
clientIP: this.clientIP,
trackedConnections: this.connectionTracker.size,
connections: Array.from(this.connectionTracker.values()).map(conn => ({
connectionId: conn.connectionId,
createdAt: new Date(conn.createdAt).toISOString(),
lastUsed: new Date(conn.lastUsed).toISOString(),
userAgent: conn.userAgent
}))
};
}
}
// 導出單例實例
export const ipConnectionManager = IPBasedConnectionManager.getInstance();

View File

@@ -1,280 +0,0 @@
// =====================================================
// 智能連線清理器
// =====================================================
import mysql from 'mysql2/promise';
import { db } from './database';
import { smartIPDetector } from './smart-ip-detector';
import { NextRequest } from 'next/server';
export interface CleanupResult {
success: boolean;
killedCount: number;
message: string;
details: {
userRealIP?: string;
infrastructureIPs?: string[];
cleanedConnections: Array<{
id: number;
host: string;
time: number;
state: string;
}>;
};
}
export class SmartConnectionCleaner {
private static instance: SmartConnectionCleaner;
public static getInstance(): SmartConnectionCleaner {
if (!SmartConnectionCleaner.instance) {
SmartConnectionCleaner.instance = new SmartConnectionCleaner();
}
return SmartConnectionCleaner.instance;
}
// 智能清理連線
public async smartCleanup(request: NextRequest): Promise<CleanupResult> {
try {
// 1. 使用智能 IP 偵測器獲取真實 IP
const ipDetection = smartIPDetector.detectClientIP(request);
const userRealIP = ipDetection.detectedIP;
console.log('🧠 智能清理開始:', {
detectedIP: userRealIP,
confidence: ipDetection.confidence,
source: ipDetection.source,
isUserRealIP: ipDetection.isUserRealIP,
infrastructureIPs: ipDetection.infrastructureIPs
});
// 2. 建立資料庫連線
const connection = await db.getConnection();
let killedCount = 0;
const cleanedConnections: Array<{
id: number;
host: string;
time: number;
state: string;
}> = [];
try {
// 3. 獲取所有相關連線
const [allConnections] = await connection.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(`🔍 找到 ${allConnections.length} 個總連線`);
// 4. 分類連線
const userConnections = allConnections.filter((conn: any) =>
this.isUserConnection(conn.HOST, userRealIP)
);
const infrastructureConnections = allConnections.filter((conn: any) =>
this.isInfrastructureConnection(conn.HOST)
);
console.log(`👤 用戶連線: ${userConnections.length}`);
console.log(`🏗️ 基礎設施連線: ${infrastructureConnections.length}`);
// 5. 清理用戶連線(優先)
if (userConnections.length > 0) {
console.log(`🧹 開始清理用戶連線 (IP: ${userRealIP})`);
for (const conn of userConnections) {
if (conn.ID !== connection.threadId) {
try {
await connection.execute(`KILL ${conn.ID}`);
console.log(`💀 已殺死用戶連線 ${conn.ID} (HOST: ${conn.HOST})`);
killedCount++;
cleanedConnections.push({
id: conn.ID,
host: conn.HOST,
time: conn.TIME,
state: conn.STATE || 'Sleep'
});
} catch (error: any) {
console.log(`⚠️ 無法殺死用戶連線 ${conn.ID}: ${error.message}`);
}
}
}
}
// 6. 清理基礎設施連線(可選,根據配置)
const shouldCleanInfrastructure = process.env.CLEAN_INFRASTRUCTURE_CONNECTIONS === 'true';
if (shouldCleanInfrastructure && infrastructureConnections.length > 0) {
console.log(`🧹 開始清理基礎設施連線`);
for (const conn of infrastructureConnections) {
if (conn.ID !== connection.threadId) {
try {
await connection.execute(`KILL ${conn.ID}`);
console.log(`💀 已殺死基礎設施連線 ${conn.ID} (HOST: ${conn.HOST})`);
killedCount++;
cleanedConnections.push({
id: conn.ID,
host: conn.HOST,
time: conn.TIME,
state: conn.STATE || 'Sleep'
});
} catch (error: any) {
console.log(`⚠️ 無法殺死基礎設施連線 ${conn.ID}: ${error.message}`);
}
}
}
}
console.log(`✅ 智能清理完成: 共清理 ${killedCount} 個連線`);
return {
success: true,
killedCount,
message: `智能清理完成: 共清理 ${killedCount} 個連線`,
details: {
userRealIP: userRealIP !== 'unknown' ? userRealIP : undefined,
infrastructureIPs: ipDetection.infrastructureIPs,
cleanedConnections
}
};
} finally {
connection.release();
}
} catch (error) {
console.error('❌ 智能清理失敗:', error);
return {
success: false,
killedCount: 0,
message: `智能清理失敗: ${error instanceof Error ? error.message : '未知錯誤'}`,
details: {
cleanedConnections: []
}
};
}
}
// 檢查是否為用戶連線
private isUserConnection(host: string, userIP: string): boolean {
if (!host || !userIP || userIP === 'unknown') return false;
// 直接匹配用戶 IP
if (host.includes(userIP)) return true;
// 匹配用戶 IP 的變體格式
const ipVariants = [
userIP,
userIP.replace(/\./g, '-'), // 61.227.253.171 -> 61-227-253-171
userIP.replace(/\./g, '_'), // 61.227.253.171 -> 61_227_253_171
];
return ipVariants.some(variant => host.includes(variant));
}
// 檢查是否為基礎設施連線
private isInfrastructureConnection(host: string): boolean {
if (!host) return false;
// AWS EC2 實例
if (host.includes('ec2-') && host.includes('.amazonaws.com')) return true;
// 其他基礎設施模式
const infrastructurePatterns = [
'.amazonaws.com',
'.vercel.app',
'vercel',
'cloudflare',
'fastly.com',
'cloudfront.net'
];
return infrastructurePatterns.some(pattern => host.includes(pattern));
}
// 獲取連線統計
public async getConnectionStats(): Promise<{
total: number;
user: number;
infrastructure: number;
other: number;
details: Array<{
id: number;
host: string;
time: number;
state: string;
type: 'user' | 'infrastructure' | 'other';
}>;
}> {
try {
const connection = await db.getConnection();
try {
const [connections] = await connection.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']);
const stats = {
total: connections.length,
user: 0,
infrastructure: 0,
other: 0,
details: [] as Array<{
id: number;
host: string;
time: number;
state: string;
type: 'user' | 'infrastructure' | 'other';
}>
};
for (const conn of connections) {
let type: 'user' | 'infrastructure' | 'other' = 'other';
if (this.isInfrastructureConnection(conn.HOST)) {
type = 'infrastructure';
stats.infrastructure++;
} else if (this.isUserConnection(conn.HOST, 'unknown')) {
type = 'user';
stats.user++;
} else {
stats.other++;
}
stats.details.push({
id: conn.ID,
host: conn.HOST,
time: conn.TIME,
state: conn.STATE || 'Sleep',
type
});
}
return stats;
} finally {
connection.release();
}
} catch (error) {
console.error('❌ 獲取連線統計失敗:', error);
return {
total: 0,
user: 0,
infrastructure: 0,
other: 0,
details: []
};
}
}
}
// 導出單例實例
export const smartConnectionCleaner = SmartConnectionCleaner.getInstance();

View File

@@ -1,202 +0,0 @@
// =====================================================
// 智能連線池包裝器
// =====================================================
import { db } from './database';
import { dbFailover } from './database-failover';
import { connectionLifecycleManager } from './connection-lifecycle-manager';
export class SmartConnectionPool {
private static instance: SmartConnectionPool;
private connectionCounter = 0;
private constructor() {}
public static getInstance(): SmartConnectionPool {
if (!SmartConnectionPool.instance) {
SmartConnectionPool.instance = new SmartConnectionPool();
}
return SmartConnectionPool.instance;
}
// 獲取智能連線
public async getSmartConnection(metadata?: {
userId?: string;
sessionId?: string;
requestId?: string;
}): Promise<{
connection: any;
connectionId: string;
release: () => void;
}> {
const connectionId = `conn_${++this.connectionCounter}_${Date.now()}`;
try {
// 獲取實際連線
const connection = await db.getConnection();
// 註冊到生命週期管理器
connectionLifecycleManager.registerConnection(connectionId, connection, metadata);
// 創建包裝的釋放函數
const release = () => {
connectionLifecycleManager.releaseConnection(connectionId);
};
console.log(`🔗 獲取智能連線: ${connectionId}`);
return {
connection,
connectionId,
release
};
} catch (error) {
console.error(`❌ 獲取智能連線失敗: ${connectionId}`, error);
throw error;
}
}
// 執行智能查詢
public async executeQuery<T = any>(
sql: string,
params?: any[],
metadata?: {
userId?: string;
sessionId?: string;
requestId?: string;
}
): Promise<T[]> {
const { connection, connectionId, release } = await this.getSmartConnection(metadata);
try {
// 更新連線使用時間
connectionLifecycleManager.updateConnectionUsage(connectionId);
// 執行查詢
const [rows] = await connection.execute(sql, params);
return rows as T[];
} catch (error) {
console.error(`❌ 智能查詢失敗: ${connectionId}`, error);
throw error;
} finally {
// 確保釋放連線
release();
}
}
// 執行智能單一查詢
public async executeQueryOne<T = any>(
sql: string,
params?: any[],
metadata?: {
userId?: string;
sessionId?: string;
requestId?: string;
}
): Promise<T | null> {
const results = await this.executeQuery<T>(sql, params, metadata);
return results.length > 0 ? results[0] : null;
}
// 執行智能插入
public async executeInsert(
sql: string,
params?: any[],
metadata?: {
userId?: string;
sessionId?: string;
requestId?: string;
}
): Promise<any> {
const { connection, connectionId, release } = await this.getSmartConnection(metadata);
try {
// 更新連線使用時間
connectionLifecycleManager.updateConnectionUsage(connectionId);
// 執行插入
const [result] = await connection.execute(sql, params);
return result;
} catch (error) {
console.error(`❌ 智能插入失敗: ${connectionId}`, error);
throw error;
} finally {
// 確保釋放連線
release();
}
}
// 執行智能更新
public async executeUpdate(
sql: string,
params?: any[],
metadata?: {
userId?: string;
sessionId?: string;
requestId?: string;
}
): Promise<any> {
const { connection, connectionId, release } = await this.getSmartConnection(metadata);
try {
// 更新連線使用時間
connectionLifecycleManager.updateConnectionUsage(connectionId);
// 執行更新
const [result] = await connection.execute(sql, params);
return result;
} catch (error) {
console.error(`❌ 智能更新失敗: ${connectionId}`, error);
throw error;
} finally {
// 確保釋放連線
release();
}
}
// 執行智能刪除
public async executeDelete(
sql: string,
params?: any[],
metadata?: {
userId?: string;
sessionId?: string;
requestId?: string;
}
): Promise<any> {
const { connection, connectionId, release } = await this.getSmartConnection(metadata);
try {
// 更新連線使用時間
connectionLifecycleManager.updateConnectionUsage(connectionId);
// 執行刪除
const [result] = await connection.execute(sql, params);
return result;
} catch (error) {
console.error(`❌ 智能刪除失敗: ${connectionId}`, error);
throw error;
} finally {
// 確保釋放連線
release();
}
}
// 獲取連線統計
public getConnectionStats() {
return connectionLifecycleManager.getConnectionStats();
}
// 強制清理所有連線
public forceCleanup() {
connectionLifecycleManager.forceCleanupAll();
}
// 設置清理參數
public setCleanupParams(maxIdleTime?: number, maxConnectionAge?: number) {
connectionLifecycleManager.setCleanupParams(maxIdleTime, maxConnectionAge);
}
}
// 導出單例實例
export const smartPool = SmartConnectionPool.getInstance();

View File

@@ -1,153 +0,0 @@
// =====================================================
// 智能 IP 連線池
// =====================================================
import { db } from './database';
import { ipConnectionManager } from './ip-based-connection-manager';
export class SmartIPConnectionPool {
private static instance: SmartIPConnectionPool;
private connectionCounter = 0;
private constructor() {}
public static getInstance(): SmartIPConnectionPool {
if (!SmartIPConnectionPool.instance) {
SmartIPConnectionPool.instance = new SmartIPConnectionPool();
}
return SmartIPConnectionPool.instance;
}
// 設置客戶端 IP
public setClientIP(ip: string) {
ipConnectionManager.setClientIP(ip);
}
// 獲取智能連線(帶 IP 追蹤)
public async getSmartConnection(metadata?: {
userAgent?: string;
requestId?: string;
clientIP?: string;
}): Promise<{
connection: any;
connectionId: string;
release: () => void;
}> {
const connectionId = `conn_${++this.connectionCounter}_${Date.now()}`;
// 設置客戶端 IP
if (metadata?.clientIP) {
ipConnectionManager.setClientIP(metadata.clientIP);
}
try {
// 獲取實際連線
const connection = await db.getConnection();
// 註冊到 IP 連線管理器
ipConnectionManager.registerConnection(connectionId, {
userAgent: metadata?.userAgent,
requestId: metadata?.requestId
});
// 創建包裝的釋放函數
const release = () => {
ipConnectionManager.releaseConnection(connectionId);
};
console.log(`🔗 獲取智能 IP 連線: ${connectionId}`);
return {
connection,
connectionId,
release
};
} catch (error) {
console.error(`❌ 獲取智能 IP 連線失敗: ${connectionId}`, error);
throw error;
}
}
// 執行智能查詢(帶 IP 追蹤)
public async executeQuery<T = any>(
sql: string,
params?: any[],
metadata?: {
userAgent?: string;
requestId?: string;
clientIP?: string;
}
): Promise<T[]> {
const { connection, connectionId, release } = await this.getSmartConnection(metadata);
try {
// 更新連線使用時間
ipConnectionManager.updateConnectionUsage(connectionId);
// 執行查詢
const [rows] = await connection.execute(sql, params);
return rows as T[];
} catch (error) {
console.error(`❌ 智能 IP 查詢失敗: ${connectionId}`, error);
throw error;
} finally {
// 確保釋放連線
release();
}
}
// 執行智能單一查詢
public async executeQueryOne<T = any>(
sql: string,
params?: any[],
metadata?: {
userAgent?: string;
requestId?: string;
clientIP?: string;
}
): Promise<T | null> {
const results = await this.executeQuery<T>(sql, params, metadata);
return results.length > 0 ? results[0] : null;
}
// 清理當前 IP 的所有連線
public async cleanupCurrentIPConnections(): Promise<{
success: boolean;
killedCount: number;
message: string;
}> {
return await ipConnectionManager.cleanupConnectionsByIP();
}
// 清理指定 IP 的所有連線
public async cleanupIPConnections(targetIP: string): Promise<{
success: boolean;
killedCount: number;
message: string;
}> {
return await ipConnectionManager.cleanupConnectionsByIP(targetIP);
}
// 獲取當前 IP 的連線狀態
public async getCurrentIPConnections() {
return await ipConnectionManager.getConnectionsByIP();
}
// 獲取指定 IP 的連線狀態
public async getIPConnections(targetIP: string) {
return await ipConnectionManager.getConnectionsByIP(targetIP);
}
// 獲取本地連線統計
public getLocalConnectionStats() {
return ipConnectionManager.getLocalConnectionStats();
}
// 清理本地追蹤的連線
public cleanupLocalConnections() {
return ipConnectionManager.cleanupLocalConnections();
}
}
// 導出單例實例
export const smartIPPool = SmartIPConnectionPool.getInstance();

View File

@@ -1,272 +0,0 @@
// =====================================================
// 智能 IP 偵測器
// =====================================================
import { NextRequest } from 'next/server';
export interface IPDetectionResult {
detectedIP: string;
confidence: 'high' | 'medium' | 'low';
source: string;
allCandidates: string[];
isPublicIP: boolean;
}
export class SmartIPDetector {
private static instance: SmartIPDetector;
public static getInstance(): SmartIPDetector {
if (!SmartIPDetector.instance) {
SmartIPDetector.instance = new SmartIPDetector();
}
return SmartIPDetector.instance;
}
// 檢查是否為公網 IP
private isPublicIP(ip: string): boolean {
if (!ip || ip === 'unknown') return false;
// 本地地址
if (ip === '127.0.0.1' || ip === '::1' || ip === 'localhost') return false;
// 私有地址範圍
if (ip.startsWith('192.168.') ||
ip.startsWith('10.') ||
ip.startsWith('172.') ||
ip.startsWith('169.254.')) return false;
// IPv6 本地地址
if (ip.startsWith('fe80:') ||
ip.startsWith('::1') ||
ip.startsWith('::ffff:127.0.0.1')) return false;
return true;
}
// 檢查是否為基礎設施 IPVercel、AWS、Cloudflare 等)
private isInfrastructureIP(ip: string): boolean {
if (!ip) return false;
// Vercel/AWS EC2 實例
if (ip.includes('ec2-') && ip.includes('.compute-1.amazonaws.com')) return true;
if (ip.includes('ec2-') && ip.includes('.amazonaws.com')) return true;
// AWS 其他服務
if (ip.includes('.amazonaws.com')) return true;
// Vercel 相關
if (ip.includes('vercel')) return true;
// Cloudflare 相關(但 cf-connecting-ip 是我們想要的)
if (ip.includes('cloudflare') && !ip.includes('cf-connecting-ip')) return true;
// 其他常見的 CDN/代理服務
const infrastructurePatterns = [
'fastly.com',
'cloudfront.net',
'akamai.net',
'maxcdn.com',
'keycdn.com'
];
return infrastructurePatterns.some(pattern => ip.includes(pattern));
}
// 檢查是否為用戶真實 IP
private isUserRealIP(ip: string): boolean {
if (!ip || ip === 'unknown') return false;
// 不是基礎設施 IP
if (this.isInfrastructureIP(ip)) return false;
// 是公網 IP
if (!this.isPublicIP(ip)) return false;
// 是有效的 IP 格式
if (!this.isValidIP(ip)) return false;
return true;
}
// 從 x-forwarded-for 解析 IP
private parseForwardedFor(forwarded: string): string[] {
if (!forwarded) return [];
return forwarded
.split(',')
.map(ip => ip.trim())
.filter(ip => ip && ip !== 'unknown');
}
// 智能偵測客戶端 IP
public detectClientIP(request: NextRequest): IPDetectionResult {
const candidates: string[] = [];
const sources: { [key: string]: string } = {};
// 1. 收集所有可能的 IP 來源
const headers = {
'x-forwarded-for': request.headers.get('x-forwarded-for'),
'x-real-ip': request.headers.get('x-real-ip'),
'cf-connecting-ip': request.headers.get('cf-connecting-ip'),
'x-client-ip': request.headers.get('x-client-ip'),
'x-forwarded': request.headers.get('x-forwarded'),
'x-cluster-client-ip': request.headers.get('x-cluster-client-ip'),
'x-original-forwarded-for': request.headers.get('x-original-forwarded-for'),
'x-remote-addr': request.headers.get('x-remote-addr'),
'remote-addr': request.headers.get('remote-addr'),
'client-ip': request.headers.get('client-ip'),
};
// 2. 從各個標頭提取 IP
Object.entries(headers).forEach(([header, value]) => {
if (value) {
if (header === 'x-forwarded-for') {
const ips = this.parseForwardedFor(value);
ips.forEach(ip => {
candidates.push(ip);
sources[ip] = header;
});
} else {
candidates.push(value);
sources[value] = header;
}
}
});
// 3. 添加 NextRequest 的 IP (如果可用)
const nextIP = (request as any).ip;
if (nextIP) {
candidates.push(nextIP);
sources[nextIP] = 'next-request';
}
// 4. 去重並過濾
const uniqueCandidates = [...new Set(candidates)].filter(ip =>
ip && ip !== 'unknown' && ip !== '::1' && ip !== '127.0.0.1'
);
console.log('🔍 IP 偵測候選:', {
candidates: uniqueCandidates,
sources: sources,
allHeaders: Object.fromEntries(request.headers.entries())
});
// 5. 智能選擇最佳 IP
let selectedIP = 'unknown';
let confidence: 'high' | 'medium' | 'low' = 'low';
let source = 'unknown';
// 優先級 1: Cloudflare IP (最高可信度) - 但要是用戶真實 IP
const cfIP = uniqueCandidates.find(ip => sources[ip] === 'cf-connecting-ip');
if (cfIP && this.isUserRealIP(cfIP)) {
selectedIP = cfIP;
confidence = 'high';
source = 'cf-connecting-ip';
}
// 優先級 2: 其他代理標頭中的用戶真實 IP
if (selectedIP === 'unknown') {
const proxyHeaders = ['x-real-ip', 'x-client-ip', 'x-cluster-client-ip'];
for (const header of proxyHeaders) {
const ip = uniqueCandidates.find(candidate => sources[candidate] === header);
if (ip && this.isUserRealIP(ip)) {
selectedIP = ip;
confidence = 'high';
source = header;
break;
}
}
}
// 優先級 3: x-forwarded-for 中的第一個用戶真實 IP
if (selectedIP === 'unknown') {
const forwardedIPs = uniqueCandidates.filter(ip => sources[ip] === 'x-forwarded-for');
const userRealIP = forwardedIPs.find(ip => this.isUserRealIP(ip));
if (userRealIP) {
selectedIP = userRealIP;
confidence = 'medium';
source = 'x-forwarded-for';
}
}
// 優先級 4: 任何用戶真實 IP
if (selectedIP === 'unknown') {
const userRealIP = uniqueCandidates.find(ip => this.isUserRealIP(ip));
if (userRealIP) {
selectedIP = userRealIP;
confidence = 'medium';
source = sources[userRealIP] || 'unknown';
}
}
// 優先級 5: 任何公網 IP非基礎設施
if (selectedIP === 'unknown') {
const publicIP = uniqueCandidates.find(ip =>
this.isPublicIP(ip) && !this.isInfrastructureIP(ip)
);
if (publicIP) {
selectedIP = publicIP;
confidence = 'low';
source = sources[publicIP] || 'unknown';
}
}
// 優先級 6: 任何非本地 IP非基礎設施
if (selectedIP === 'unknown') {
const nonLocalIP = uniqueCandidates.find(ip =>
ip !== '::1' && ip !== '127.0.0.1' &&
!ip.startsWith('192.168.') && !ip.startsWith('10.') && !ip.startsWith('172.') &&
!this.isInfrastructureIP(ip)
);
if (nonLocalIP) {
selectedIP = nonLocalIP;
confidence = 'low';
source = sources[nonLocalIP] || 'unknown';
}
}
// 優先級 7: 第一個候選 IP最後選擇
if (selectedIP === 'unknown' && uniqueCandidates.length > 0) {
selectedIP = uniqueCandidates[0];
confidence = 'low';
source = sources[selectedIP] || 'unknown';
}
const result: IPDetectionResult = {
detectedIP: selectedIP,
confidence,
source,
allCandidates: uniqueCandidates,
isPublicIP: this.isPublicIP(selectedIP)
};
console.log('🎯 IP 偵測結果:', {
...result,
isInfrastructureIP: this.isInfrastructureIP(selectedIP),
isUserRealIP: this.isUserRealIP(selectedIP),
infrastructureIPs: uniqueCandidates.filter(ip => this.isInfrastructureIP(ip)),
userRealIPs: uniqueCandidates.filter(ip => this.isUserRealIP(ip))
});
return result;
}
// 驗證 IP 格式
public isValidIP(ip: string): boolean {
if (!ip || ip === 'unknown') return false;
// IPv4 格式檢查
const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
if (ipv4Regex.test(ip)) {
const parts = ip.split('.').map(Number);
return parts.every(part => part >= 0 && part <= 255);
}
// IPv6 格式檢查(簡化)
const ipv6Regex = /^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/;
return ipv6Regex.test(ip);
}
}
// 導出單例實例
export const smartIPDetector = SmartIPDetector.getInstance();

View File

@@ -1,186 +0,0 @@
// =====================================================
// 終極連線殺手 - 強制清理所有連線
// =====================================================
import mysql from 'mysql2/promise';
export class UltimateConnectionKiller {
private static instance: UltimateConnectionKiller;
private constructor() {}
public static getInstance(): UltimateConnectionKiller {
if (!UltimateConnectionKiller.instance) {
UltimateConnectionKiller.instance = new UltimateConnectionKiller();
}
return UltimateConnectionKiller.instance;
}
// 終極清理 - 殺死所有連線
public async ultimateKill() {
console.log('💀 執行終極連線清理...');
try {
// 1. 建立一個臨時連線來執行清理
const tempConnection = await mysql.createConnection({
host: process.env.DB_HOST || '122.100.99.161',
port: parseInt(process.env.DB_PORT || '43306'),
user: process.env.DB_USER || 'A999',
password: process.env.DB_PASSWORD || '1023',
database: process.env.DB_NAME || 'db_AI_Platform',
charset: 'utf8mb4',
timezone: '+08:00',
});
try {
// 2. 獲取所有連線
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.length} 個連線需要清理`);
// 3. 殺死所有連線(除了當前連線)
let killedCount = 0;
for (const conn of connections) {
if (conn.ID !== tempConnection.threadId) {
try {
await tempConnection.execute(`KILL ${conn.ID}`);
console.log(`💀 已殺死連線 ${conn.ID} (用戶: ${conn.USER}, 時間: ${conn.TIME}s)`);
killedCount++;
} catch (error: any) {
console.log(`⚠️ 無法殺死連線 ${conn.ID}: ${error.message}`);
}
}
}
console.log(`✅ 已殺死 ${killedCount} 個連線`);
// 4. 等待連線完全關閉
console.log('⏳ 等待連線完全關閉...');
await new Promise(resolve => setTimeout(resolve, 3000));
// 5. 再次檢查狀態
const [finalConnections] = await tempConnection.execute(`
SELECT COUNT(*) as count FROM information_schema.PROCESSLIST
WHERE USER = ?
`, [process.env.DB_USER || 'A999']);
const remainingConnections = finalConnections[0].count;
console.log(`📊 清理後剩餘連線: ${remainingConnections}`);
if (remainingConnections <= 1) {
console.log('🎉 連線清理成功!');
} else {
console.warn(`⚠️ 仍有 ${remainingConnections - 1} 個連線未清理`);
}
return {
success: true,
killedCount,
remainingConnections: remainingConnections - 1, // 減去當前連線
message: `已殺死 ${killedCount} 個連線,剩餘 ${remainingConnections - 1}`
};
} finally {
// 6. 關閉臨時連線
await tempConnection.end();
console.log('🔌 臨時連線已關閉');
}
} catch (error) {
console.error('❌ 終極清理失敗:', error);
return {
success: false,
error: error instanceof Error ? error.message : '未知錯誤'
};
}
}
// 檢查連線狀態
public async checkStatus() {
try {
const tempConnection = await mysql.createConnection({
host: process.env.DB_HOST || '122.100.99.161',
port: parseInt(process.env.DB_PORT || '43306'),
user: process.env.DB_USER || 'A999',
password: process.env.DB_PASSWORD || '1023',
database: process.env.DB_NAME || 'db_AI_Platform',
charset: 'utf8mb4',
timezone: '+08:00',
});
try {
// 獲取連線統計
const [statusResult] = await tempConnection.execute(`
SHOW STATUS LIKE 'Threads_connected'
`);
const [maxConnResult] = await tempConnection.execute(`
SHOW VARIABLES LIKE 'max_connections'
`);
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']);
const currentConnections = statusResult[0]?.Value || 0;
const maxConnections = maxConnResult[0]?.Value || 100;
const usagePercentage = (currentConnections / maxConnections) * 100;
return {
currentConnections: parseInt(currentConnections),
maxConnections: parseInt(maxConnections),
usagePercentage,
connectionDetails: connections,
connectionCount: connections.length
};
} finally {
await tempConnection.end();
}
} catch (error) {
console.error('❌ 檢查狀態失敗:', error);
return null;
}
}
// 強制重啟資料庫連線
public async forceRestart() {
console.log('🔄 強制重啟資料庫連線...');
try {
// 1. 先殺死所有連線
await this.ultimateKill();
// 2. 等待一段時間
console.log('⏳ 等待系統穩定...');
await new Promise(resolve => setTimeout(resolve, 5000));
// 3. 檢查狀態
const status = await this.checkStatus();
if (status && status.connectionCount <= 1) {
console.log('✅ 資料庫連線重啟成功');
return { success: true, message: '資料庫連線重啟成功' };
} else {
console.warn('⚠️ 資料庫連線重啟後仍有連線存在');
return { success: false, message: '重啟後仍有連線存在' };
}
} catch (error) {
console.error('❌ 強制重啟失敗:', error);
return { success: false, error: error instanceof Error ? error.message : '未知錯誤' };
}
}
}
// 導出單例實例
export const ultimateKiller = UltimateConnectionKiller.getInstance();