修復 too many connection 問題
This commit is contained in:
197
lib/database-shutdown-manager.ts
Normal file
197
lib/database-shutdown-manager.ts
Normal file
@@ -0,0 +1,197 @@
|
||||
// =====================================================
|
||||
// 資料庫關閉管理器
|
||||
// =====================================================
|
||||
|
||||
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;
|
||||
private isShuttingDown = false;
|
||||
private shutdownHandlers: (() => Promise<void>)[] = [];
|
||||
|
||||
private constructor() {
|
||||
this.registerShutdownHandlers();
|
||||
}
|
||||
|
||||
public static getInstance(): DatabaseShutdownManager {
|
||||
if (!DatabaseShutdownManager.instance) {
|
||||
DatabaseShutdownManager.instance = new DatabaseShutdownManager();
|
||||
}
|
||||
return DatabaseShutdownManager.instance;
|
||||
}
|
||||
|
||||
// 註冊關閉處理器
|
||||
private registerShutdownHandlers() {
|
||||
// 添加資料庫關閉處理器
|
||||
this.addShutdownHandler('database', async () => {
|
||||
console.log('🔄 正在關閉主要資料庫連線池...');
|
||||
try {
|
||||
await db.close();
|
||||
console.log('✅ 主要資料庫連線池已關閉');
|
||||
} catch (error) {
|
||||
console.error('❌ 關閉主要資料庫連線池時發生錯誤:', error);
|
||||
}
|
||||
});
|
||||
|
||||
// 添加備援資料庫關閉處理器
|
||||
this.addShutdownHandler('failover', async () => {
|
||||
console.log('🔄 正在關閉備援資料庫連線池...');
|
||||
try {
|
||||
await dbFailover.close();
|
||||
console.log('✅ 備援資料庫連線池已關閉');
|
||||
} catch (error) {
|
||||
console.error('❌ 關閉備援資料庫連線池時發生錯誤:', error);
|
||||
}
|
||||
});
|
||||
|
||||
// 添加監控服務關閉處理器
|
||||
this.addShutdownHandler('monitor', async () => {
|
||||
console.log('🔄 正在停止資料庫監控服務...');
|
||||
try {
|
||||
dbMonitor.stopMonitoring();
|
||||
console.log('✅ 資料庫監控服務已停止');
|
||||
} catch (error) {
|
||||
console.error('❌ 停止資料庫監控服務時發生錯誤:', error);
|
||||
}
|
||||
});
|
||||
|
||||
// 添加智能連線池關閉處理器
|
||||
this.addShutdownHandler('smart-pool', async () => {
|
||||
console.log('🔄 正在清理智能連線池...');
|
||||
try {
|
||||
smartPool.forceCleanup();
|
||||
console.log('✅ 智能連線池已清理');
|
||||
} catch (error) {
|
||||
console.error('❌ 清理智能連線池時發生錯誤:', error);
|
||||
}
|
||||
});
|
||||
|
||||
// 註冊系統信號處理器
|
||||
this.registerSystemHandlers();
|
||||
}
|
||||
|
||||
// 添加關閉處理器
|
||||
public addShutdownHandler(name: string, handler: () => Promise<void>) {
|
||||
this.shutdownHandlers.push(async () => {
|
||||
try {
|
||||
console.log(`🔄 執行關閉處理器: ${name}`);
|
||||
await handler();
|
||||
console.log(`✅ 關閉處理器完成: ${name}`);
|
||||
} catch (error) {
|
||||
console.error(`❌ 關閉處理器失敗: ${name}`, error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 註冊系統信號處理器
|
||||
private registerSystemHandlers() {
|
||||
if (typeof process === 'undefined') return;
|
||||
|
||||
// SIGINT (Ctrl+C)
|
||||
process.on('SIGINT', () => {
|
||||
console.log('\n🛑 收到 SIGINT 信號,開始優雅關閉...');
|
||||
this.gracefulShutdown();
|
||||
});
|
||||
|
||||
// SIGTERM (終止信號)
|
||||
process.on('SIGTERM', () => {
|
||||
console.log('\n🛑 收到 SIGTERM 信號,開始優雅關閉...');
|
||||
this.gracefulShutdown();
|
||||
});
|
||||
|
||||
// 未捕獲的異常
|
||||
process.on('uncaughtException', (error) => {
|
||||
console.error('❌ 未捕獲的異常:', error);
|
||||
this.gracefulShutdown();
|
||||
});
|
||||
|
||||
// 未處理的 Promise 拒絕
|
||||
process.on('unhandledRejection', (reason, promise) => {
|
||||
console.error('❌ 未處理的 Promise 拒絕:', reason);
|
||||
this.gracefulShutdown();
|
||||
});
|
||||
|
||||
// 程序退出
|
||||
process.on('exit', () => {
|
||||
if (!this.isShuttingDown) {
|
||||
console.log('🛑 程序即將退出,強制關閉資料庫連線...');
|
||||
this.forceShutdown();
|
||||
}
|
||||
});
|
||||
|
||||
console.log('✅ 系統信號處理器已註冊');
|
||||
}
|
||||
|
||||
// 優雅關閉
|
||||
public async gracefulShutdown() {
|
||||
if (this.isShuttingDown) {
|
||||
console.log('⚠️ 關閉程序已在進行中,跳過重複請求');
|
||||
return;
|
||||
}
|
||||
|
||||
this.isShuttingDown = true;
|
||||
console.log('🔄 開始優雅關閉資料庫連線...');
|
||||
|
||||
const startTime = Date.now();
|
||||
|
||||
try {
|
||||
// 並行執行所有關閉處理器
|
||||
await Promise.allSettled(
|
||||
this.shutdownHandlers.map(handler => handler())
|
||||
);
|
||||
|
||||
const duration = Date.now() - startTime;
|
||||
console.log(`✅ 資料庫連線關閉完成,耗時: ${duration}ms`);
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 優雅關閉過程中發生錯誤:', error);
|
||||
} finally {
|
||||
// 強制退出程序
|
||||
setTimeout(() => {
|
||||
console.log('🛑 強制退出程序');
|
||||
process.exit(0);
|
||||
}, 5000); // 5秒後強制退出
|
||||
}
|
||||
}
|
||||
|
||||
// 強制關閉
|
||||
public forceShutdown() {
|
||||
console.log('🚨 強制關閉所有資料庫連線...');
|
||||
|
||||
// 同步執行關閉處理器(不等待)
|
||||
this.shutdownHandlers.forEach(handler => {
|
||||
try {
|
||||
handler();
|
||||
} catch (error) {
|
||||
console.error('❌ 強制關閉時發生錯誤:', error);
|
||||
}
|
||||
});
|
||||
|
||||
console.log('✅ 強制關閉完成');
|
||||
}
|
||||
|
||||
// 獲取關閉狀態
|
||||
public getShutdownStatus() {
|
||||
return {
|
||||
isShuttingDown: this.isShuttingDown,
|
||||
handlerCount: this.shutdownHandlers.length,
|
||||
registeredHandlers: this.shutdownHandlers.map((_, index) => `handler-${index}`)
|
||||
};
|
||||
}
|
||||
|
||||
// 測試關閉機制
|
||||
public async testShutdown() {
|
||||
console.log('🧪 測試資料庫關閉機制...');
|
||||
await this.gracefulShutdown();
|
||||
}
|
||||
}
|
||||
|
||||
// 導出單例實例
|
||||
export const dbShutdownManager = DatabaseShutdownManager.getInstance();
|
||||
|
||||
// 導出便捷函數
|
||||
export const gracefulShutdown = () => dbShutdownManager.gracefulShutdown();
|
||||
export const forceShutdown = () => dbShutdownManager.forceShutdown();
|
Reference in New Issue
Block a user