Initial commit
This commit is contained in:
234
lib/database.ts.bkp
Normal file
234
lib/database.ts.bkp
Normal file
@@ -0,0 +1,234 @@
|
||||
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)
|
||||
})
|
||||
Reference in New Issue
Block a user