/** * Espera a que PostgreSQL responda y que el esquema CloudRestore (Alembic a24c) * esté aplicado antes de arrancar el panel HTTPS. */ import { fileURLToPath } from 'url'; import pg from 'pg'; const { Pool } = pg; const REQUIRED_TABLES = ['restore_targets', 'cloudrestore_status', 'restore_job_logs']; function envInt(name, fallback) { const raw = process.env[name]; if (!raw) return fallback; const n = Number.parseInt(raw, 10); return Number.isFinite(n) && n > 0 ? n : fallback; } function poolConfig() { return { host: process.env.DB_POSTGRES_HOST || 'localhost', port: Number.parseInt(process.env.DB_POSTGRES_PORT || '5432', 10), database: process.env.DB_POSTGRES_DB || 'a24c', user: process.env.DB_POSTGRES_USER || 'postgres', password: process.env.DB_POSTGRES_PASS || 'postgres', max: 1, connectionTimeoutMillis: 5000, }; } async function postgresReady(pool) { await pool.query('SELECT 1'); } async function tablesReady(pool) { const r = await pool.query( ` SELECT table_name FROM information_schema.tables WHERE table_schema = 'a24c' AND table_name = ANY($1::text[]) `, [REQUIRED_TABLES] ); return r.rows.length === REQUIRED_TABLES.length; } function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } export async function waitForA24cSchema() { const maxAttempts = envInt('A24C_SCHEMA_WAIT_ATTEMPTS', 60); const intervalMs = envInt('A24C_SCHEMA_WAIT_INTERVAL_MS', 2000); const pool = new Pool(poolConfig()); console.log('=========================================='); console.log('Panel — esperando esquema a24c (CloudRestore)'); console.log(` host: ${poolConfig().host}:${poolConfig().port}`); console.log(` db: ${poolConfig().database}`); console.log('=========================================='); try { for (let attempt = 1; attempt <= maxAttempts; attempt++) { try { await postgresReady(pool); if (await tablesReady(pool)) { console.log('✓ PostgreSQL y esquema CloudRestore listos'); return; } console.log( ` intento ${attempt}/${maxAttempts}: tablas CRA pendientes (levanta a24c-backend si aún no corre)` ); } catch (err) { const msg = err instanceof Error ? err.message : String(err); console.log(` intento ${attempt}/${maxAttempts}: ${msg}`); } if (attempt < maxAttempts) { await sleep(intervalMs); } } throw new Error( 'Timeout esperando esquema CloudRestore. Orden recomendado: ' + 'a24c-postgres → a24c-backend (alembic upgrade head) → panel' ); } finally { await pool.end(); } } if (process.argv[1] === fileURLToPath(import.meta.url)) { waitForA24cSchema().catch((err) => { console.error('❌', err instanceof Error ? err.message : err); process.exit(1); }); }