Files
seguidorDeLotes/nuxt4/server/utils/db.ts
josedario87 2d532e42c6
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m4s
Agregar retry logic para conexión inicial a PostgreSQL
- Implementar 5 reintentos con 2s de delay entre cada uno
- Resolver error de autenticación en primera carga
- PostgreSQL necesita tiempo para ejecutar 00_configure_auth.sh
- App ahora espera automáticamente hasta que auth esté configurado

Esto resuelve el error 28P01 (password authentication failed)
que ocurría solo en la primera conexión después del deploy.
2025-11-21 20:04:42 -06:00

132 lines
3.5 KiB
TypeScript

import pg from 'pg'
const { Pool } = pg
let pool: pg.Pool | null = null
/**
* Obtiene o crea el pool de conexiones a PostgreSQL.
* Usa variables de entorno para la configuración.
*/
export function getPool(): pg.Pool {
if (!pool) {
const config = {
user: process.env.POSTGRES_USER || 'seguidor',
password: process.env.POSTGRES_PASSWORD || 'seguidor_password',
database: process.env.POSTGRES_DB || 'seguidor_lotes',
host: process.env.POSTGRES_HOST || 'postgres',
port: parseInt(process.env.POSTGRES_PORT || '5432'),
max: 20, // máximo de conexiones en el pool
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 10000, // Aumentado a 10s para la primera conexión
}
pool = new Pool(config)
// Manejo de errores del pool
pool.on('error', (err) => {
console.error('Error inesperado en el pool de PostgreSQL:', err)
})
// Solo log en desarrollo para reducir ruido
if (process.env.NODE_ENV !== 'production') {
pool.on('connect', () => {
console.log('Nueva conexión establecida con PostgreSQL')
})
}
// Verificar conexión inicial con retry
let retries = 5
const tryConnect = async () => {
try {
const client = await pool!.connect()
console.log('✅ Conexión inicial a PostgreSQL exitosa')
client.release()
} catch (err: any) {
retries--
if (retries > 0) {
console.log(`⚠️ Conexión a PostgreSQL falló, reintentando... (${retries} intentos restantes)`)
setTimeout(tryConnect, 2000) // Reintentar en 2 segundos
} else {
console.error('❌ No se pudo conectar a PostgreSQL después de varios intentos:', err.message)
}
}
}
// Ejecutar verificación inicial en background
tryConnect()
}
return pool
}
/**
* Ejecuta una query SQL con parámetros.
* Wrapper seguro para evitar inyección SQL.
*
* @param text - Query SQL con placeholders $1, $2, etc.
* @param params - Parámetros para la query
* @returns Resultado de la query
*/
export async function query<T = any>(
text: string,
params?: any[]
): Promise<pg.QueryResult<T>> {
const pool = getPool()
const start = Date.now()
try {
const result = await pool.query<T>(text, params)
const duration = Date.now() - start
// Log solo en desarrollo
if (process.env.NODE_ENV !== 'production') {
console.log('Query ejecutada:', { text, duration: `${duration}ms`, rows: result.rowCount })
}
return result
} catch (error) {
console.error('Error ejecutando query:', { text, params, error })
throw error
}
}
/**
* Obtiene un cliente del pool para ejecutar transacciones.
* IMPORTANTE: Debes llamar a client.release() al terminar.
*
* @returns Cliente de PostgreSQL
*/
export async function getClient(): Promise<pg.PoolClient> {
const pool = getPool()
return await pool.connect()
}
/**
* Cierra el pool de conexiones.
* Útil para tests o shutdown graceful.
*/
export async function closePool(): Promise<void> {
if (pool) {
await pool.end()
pool = null
console.log('Pool de PostgreSQL cerrado')
}
}
/**
* Verifica que la conexión a la base de datos esté funcionando.
* Útil para health checks.
*
* @returns true si la conexión está OK, false en caso contrario
*/
export async function checkConnection(): Promise<boolean> {
try {
const result = await query('SELECT NOW() as now')
return result.rows.length > 0
} catch (error) {
console.error('Error verificando conexión a PostgreSQL:', error)
return false
}
}