修正分頁、Too many connection 問題
This commit is contained in:
156
lib/database-middleware.ts
Normal file
156
lib/database-middleware.ts
Normal file
@@ -0,0 +1,156 @@
|
||||
// =====================================================
|
||||
// 資料庫連線管理中間件
|
||||
// =====================================================
|
||||
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { db } from './database';
|
||||
import { dbMonitor } from './database-monitor';
|
||||
|
||||
// 連線池狀態追蹤
|
||||
let connectionCount = 0;
|
||||
const maxConnections = 3; // 與資料庫配置保持一致
|
||||
|
||||
export function withDatabaseConnection<T extends any[]>(
|
||||
handler: (...args: T) => Promise<NextResponse>
|
||||
) {
|
||||
return async (...args: T): Promise<NextResponse> => {
|
||||
// 檢查連線池狀態
|
||||
if (connectionCount >= maxConnections) {
|
||||
console.warn(`⚠️ 連線池已滿 (${connectionCount}/${maxConnections}),等待可用連線...`);
|
||||
|
||||
// 等待一段時間後重試
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
|
||||
if (connectionCount >= maxConnections) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: '資料庫連線池已滿,請稍後再試',
|
||||
retryAfter: 5 // 建議5秒後重試
|
||||
},
|
||||
{ status: 503 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
connectionCount++;
|
||||
|
||||
try {
|
||||
const result = await handler(...args);
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('資料庫操作錯誤:', error);
|
||||
|
||||
// 根據錯誤類型返回適當的響應
|
||||
if (error instanceof Error) {
|
||||
if (error.message.includes('ER_CON_COUNT_ERROR')) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: '資料庫連線數已達上限,請稍後再試',
|
||||
retryAfter: 10
|
||||
},
|
||||
{ status: 503 }
|
||||
);
|
||||
} else if (error.message.includes('ECONNRESET') || error.message.includes('PROTOCOL_CONNECTION_LOST')) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: '資料庫連線中斷,請重試',
|
||||
retryAfter: 3
|
||||
},
|
||||
{ status: 503 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: '資料庫操作失敗',
|
||||
details: error instanceof Error ? error.message : '未知錯誤'
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
} finally {
|
||||
connectionCount--;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 連線池健康檢查
|
||||
export async function checkConnectionHealth(): Promise<{
|
||||
isHealthy: boolean;
|
||||
connectionCount: number;
|
||||
maxConnections: number;
|
||||
usagePercentage: number;
|
||||
}> {
|
||||
try {
|
||||
const stats = dbMonitor.getConnectionStats();
|
||||
|
||||
return {
|
||||
isHealthy: stats.usagePercentage < 80,
|
||||
connectionCount: stats.currentConnections,
|
||||
maxConnections: stats.maxConnections,
|
||||
usagePercentage: stats.usagePercentage
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('連線健康檢查失敗:', error);
|
||||
return {
|
||||
isHealthy: false,
|
||||
connectionCount: 0,
|
||||
maxConnections: 0,
|
||||
usagePercentage: 100
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 自動釋放空閒連線
|
||||
export async function autoReleaseIdleConnections(): Promise<boolean> {
|
||||
try {
|
||||
const health = await checkConnectionHealth();
|
||||
|
||||
if (health.usagePercentage > 70) {
|
||||
console.log('🔄 連線使用率過高,嘗試釋放空閒連線...');
|
||||
return await dbMonitor.releaseIdleConnections();
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('自動釋放連線失敗:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 連線池監控
|
||||
export function startConnectionMonitoring() {
|
||||
// 每30秒檢查一次連線狀態
|
||||
dbMonitor.startMonitoring(30000);
|
||||
|
||||
// 每5分鐘嘗試釋放空閒連線
|
||||
setInterval(async () => {
|
||||
await autoReleaseIdleConnections();
|
||||
}, 5 * 60 * 1000);
|
||||
|
||||
console.log('🔍 資料庫連線監控已啟動');
|
||||
}
|
||||
|
||||
// 優雅的關閉
|
||||
export async function gracefulShutdown() {
|
||||
console.log('🔄 正在優雅關閉資料庫連線...');
|
||||
|
||||
try {
|
||||
dbMonitor.stopMonitoring();
|
||||
await db.close();
|
||||
console.log('✅ 資料庫連線已關閉');
|
||||
} catch (error) {
|
||||
console.error('❌ 關閉資料庫連線時發生錯誤:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 處理程序退出事件
|
||||
if (typeof process !== 'undefined') {
|
||||
process.on('SIGINT', gracefulShutdown);
|
||||
process.on('SIGTERM', gracefulShutdown);
|
||||
process.on('exit', gracefulShutdown);
|
||||
}
|
Reference in New Issue
Block a user