Files
mamad-app/lib/database.ts.bkp
2025-06-22 00:01:22 +03:00

235 lines
6.0 KiB
Plaintext

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: 10, // Maximum number of connections in pool
acquireTimeout: 60000, // Maximum time to wait for a connection (60 seconds)
timeout: 60000, // Maximum time for a query (60 seconds)
reconnect: true,
idleTimeout: 300000, // Close idle connections after 5 minutes
maxIdle: 5, // Maximum idle connections
enableKeepAlive: true,
keepAliveInitialDelay: 0,
}
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)
if (err.code === "PROTOCOL_CONNECTION_LOST") {
console.log("Recreating database pool...")
pool = null
createPool()
}
})
} catch (error) {
console.error("Failed to create database pool:", error)
throw error
}
}
return pool
}
// Get connection from pool
export async function getConnection(): Promise<mysql.PoolConnection> {
try {
const connectionPool = createPool()
const connection = await connectionPool.getConnection()
// Set connection timeout
await connection.query("SET SESSION wait_timeout = 300") // 5 minutes
await connection.query("SET SESSION interactive_timeout = 300")
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)
})