import mysql from "mysql2/promise" import config from "../config.json" // Connection pool configuration const poolConfig = { host: config.database.host, user: config.database.user, password: config.database.password, database: config.database.database, charset: "utf8mb4", connectionLimit: 5, // Reduced from 10 acquireTimeout: 30000, // Reduced from 60 seconds timeout: 30000, // Reduced from 60 seconds reconnect: true, idleTimeout: 180000, // Reduced to 3 minutes maxIdle: 2, // Reduced from 5 enableKeepAlive: true, keepAliveInitialDelay: 0, // Add these to prevent excessive connections queueLimit: 0, dateStrings: false, debug: false, } let pool: mysql.Pool | null = null // Create connection pool export function createPool() { if (!pool) { try { pool = mysql.createPool(poolConfig) console.log("Database connection pool created successfully") // Handle pool events pool.on("connection", (connection) => { console.log(`New database connection established as id ${connection.threadId}`) }) pool.on("error", (err) => { console.error("Database pool error:", err) // Don't recreate pool automatically - let it handle reconnections if (err.code === "PROTOCOL_CONNECTION_LOST") { console.log("Connection lost, pool will handle reconnection automatically") } }) pool.on("acquire", (connection) => { console.log(`Connection ${connection.threadId} acquired from pool`) }) pool.on("release", (connection) => { console.log(`Connection ${connection.threadId} released back to pool`) }) } catch (error) { console.error("Failed to create database pool:", error) throw error } } return pool } // Get connection from pool export async function getConnection(): Promise { try { const connectionPool = createPool() const connection = await connectionPool.getConnection() // Don't set session timeouts - let pool handle this return connection } catch (error) { console.error("Failed to get database connection:", error) throw new Error("Database connection failed") } } // Execute query with automatic connection management export async function executeQuery(query: string, params: any[] = []) { let connection: mysql.PoolConnection | null = null try { connection = await getConnection() const [results] = await connection.execute(query, params) return results } catch (error) { console.error("Query execution failed:", error) console.error("Query:", query) console.error("Params:", params) throw error } finally { // Always release connection back to pool if (connection) { connection.release() } } } // Safe query execution with automatic parameter binding and connection management export async function safeQuery(query: string, params: any[] = []) { try { return await executeQuery(query, params) } catch (error) { console.error("Database query error:", error) throw new Error("Database operation failed") } } // Execute transaction with automatic connection management export async function executeTransaction(queries: Array<{ query: string; params?: any[] }>) { let connection: mysql.PoolConnection | null = null try { connection = await getConnection() // Start transaction await connection.beginTransaction() const results = [] // Execute all queries in transaction for (const { query, params = [] } of queries) { const [result] = await connection.execute(query, params) results.push(result) } // Commit transaction await connection.commit() return results } catch (error) { // Rollback transaction on error if (connection) { try { await connection.rollback() } catch (rollbackError) { console.error("Transaction rollback failed:", rollbackError) } } console.error("Transaction failed:", error) throw error } finally { // Always release connection back to pool if (connection) { connection.release() } } } // Test database connection and pool health export async function testConnection() { let connection: mysql.PoolConnection | null = null try { connection = await getConnection() await connection.ping() console.log("Database connection test successful") return true } catch (error) { console.error("Database connection test failed:", error) return false } finally { if (connection) { connection.release() } } } // Get pool statistics export function getPoolStats() { if (!pool) { return null } return { totalConnections: pool.pool._allConnections.length, freeConnections: pool.pool._freeConnections.length, acquiringConnections: pool.pool._acquiringConnections.length, connectionLimit: poolConfig.connectionLimit, } } // Close all connections in pool (for graceful shutdown) export async function closePool() { if (pool) { try { await pool.end() pool = null console.log("Database pool closed successfully") } catch (error) { console.error("Error closing database pool:", error) } } } // Health check for monitoring export async function healthCheck() { let connection: mysql.PoolConnection | null = null try { const startTime = Date.now() connection = await getConnection() // Test basic query const [result] = await connection.execute("SELECT 1 as health_check") const responseTime = Date.now() - startTime const stats = getPoolStats() return { status: "healthy", responseTime, poolStats: stats, timestamp: new Date().toISOString(), } } catch (error) { return { status: "unhealthy", error: error instanceof Error ? error.message : "Unknown error", timestamp: new Date().toISOString(), } } finally { if (connection) { connection.release() } } } // Initialize pool on module load // createPool() // Graceful shutdown handler process.on("SIGINT", async () => { console.log("Received SIGINT, closing database pool...") await closePool() process.exit(0) }) process.on("SIGTERM", async () => { console.log("Received SIGTERM, closing database pool...") await closePool() process.exit(0) })