All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m4s
- 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.
132 lines
3.5 KiB
TypeScript
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
|
|
}
|
|
}
|