90 lines
2.1 KiB
JavaScript
90 lines
2.1 KiB
JavaScript
const { Pool } = require("pg");
|
|
|
|
let pool = null;
|
|
|
|
/**
|
|
* Get or create a PostgreSQL connection pool.
|
|
* Uses connection pooling optimized for Lambda:
|
|
* - Reuses connections across invocations (when container is warm)
|
|
* - Small pool size to avoid exhausting database connections
|
|
*
|
|
* Expects DATABASE_URL environment variable in format:
|
|
* postgresql://user:password@host:port/database
|
|
*/
|
|
function getPool() {
|
|
if (!pool) {
|
|
const connectionString = process.env.DATABASE_URL;
|
|
|
|
if (!connectionString) {
|
|
throw new Error("DATABASE_URL environment variable is required");
|
|
}
|
|
|
|
pool = new Pool({
|
|
connectionString,
|
|
// Lambda-optimized settings
|
|
max: 1, // Single connection per Lambda instance
|
|
idleTimeoutMillis: 120000, // 2 minutes - keep connection warm
|
|
connectionTimeoutMillis: 5000, // 5 seconds to connect
|
|
});
|
|
|
|
// Handle pool errors
|
|
pool.on("error", (err) => {
|
|
console.error("Unexpected database pool error:", err);
|
|
pool = null; // Reset pool on error
|
|
});
|
|
}
|
|
|
|
return pool;
|
|
}
|
|
|
|
/**
|
|
* Execute a query with automatic connection management.
|
|
* @param {string} text - SQL query text
|
|
* @param {Array} params - Query parameters
|
|
* @returns {Promise<object>} Query result
|
|
*/
|
|
async function query(text, params) {
|
|
const pool = getPool();
|
|
const start = Date.now();
|
|
|
|
try {
|
|
const result = await pool.query(text, params);
|
|
const duration = Date.now() - start;
|
|
|
|
console.log(JSON.stringify({
|
|
level: "debug",
|
|
message: "Executed query",
|
|
query: text.substring(0, 100),
|
|
duration,
|
|
rows: result.rowCount,
|
|
}));
|
|
|
|
return result;
|
|
} catch (error) {
|
|
console.error(JSON.stringify({
|
|
level: "error",
|
|
message: "Query failed",
|
|
query: text.substring(0, 100),
|
|
error: error.message,
|
|
}));
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Close the connection pool (for cleanup).
|
|
* Call this at the end of Lambda execution if needed.
|
|
*/
|
|
async function closePool() {
|
|
if (pool) {
|
|
await pool.end();
|
|
pool = null;
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
getPool,
|
|
query,
|
|
closePool,
|
|
};
|