Files
rentall-app/lambdas/shared/db/connection.js
2026-01-13 17:14:19 -05:00

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,
};