2026-08-09 22:47:43 +02:00
|
|
|
#!/usr/bin/env node
|
|
|
|
|
/**
|
2026-08-10 01:12:21 +02:00
|
|
|
* Wait until DATABASE_URL Postgres accepts TCP connections.
|
|
|
|
|
* Works with native Postgres or Docker-mapped ports (no docker CLI required).
|
|
|
|
|
*
|
2026-08-09 22:47:43 +02:00
|
|
|
* Usage: node scripts/wait-postgres.mjs
|
|
|
|
|
*/
|
2026-08-10 01:12:21 +02:00
|
|
|
import net from "node:net";
|
2026-08-09 22:47:43 +02:00
|
|
|
import { setTimeout as delay } from "node:timers/promises";
|
2026-08-10 01:12:21 +02:00
|
|
|
import { loadRootEnv } from "./root-env.mjs";
|
2026-08-09 22:47:43 +02:00
|
|
|
|
|
|
|
|
const maxAttempts = Number(process.env.DESCRYBE_DB_WAIT_ATTEMPTS || 60);
|
|
|
|
|
const sleepMs = Number(process.env.DESCRYBE_DB_WAIT_MS || 1000);
|
|
|
|
|
|
2026-08-10 01:12:21 +02:00
|
|
|
const env = loadRootEnv(process.env);
|
|
|
|
|
const databaseUrl = env.DATABASE_URL;
|
|
|
|
|
if (!databaseUrl || !String(databaseUrl).trim()) {
|
|
|
|
|
console.error(
|
|
|
|
|
"[db] DATABASE_URL is required (root .env or shell; see .env.example)",
|
2026-08-09 22:47:43 +02:00
|
|
|
);
|
2026-08-10 01:12:21 +02:00
|
|
|
process.exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function parsePostgresTarget(urlStr) {
|
|
|
|
|
let u;
|
|
|
|
|
try {
|
|
|
|
|
u = new URL(urlStr);
|
|
|
|
|
} catch {
|
|
|
|
|
console.error("[db] DATABASE_URL is not a valid URL");
|
|
|
|
|
process.exit(1);
|
|
|
|
|
}
|
|
|
|
|
const protocol = (u.protocol || "").replace(/:$/, "");
|
|
|
|
|
if (protocol !== "postgres" && protocol !== "postgresql") {
|
|
|
|
|
console.error(`[db] DATABASE_URL must be postgres(ql)://… (got ${protocol})`);
|
|
|
|
|
process.exit(1);
|
|
|
|
|
}
|
|
|
|
|
const host = u.hostname || "127.0.0.1";
|
|
|
|
|
const port = Number(u.port || 5432);
|
|
|
|
|
if (!Number.isFinite(port) || port <= 0) {
|
|
|
|
|
console.error("[db] DATABASE_URL has an invalid port");
|
|
|
|
|
process.exit(1);
|
|
|
|
|
}
|
|
|
|
|
return { host, port };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function canConnect(host, port) {
|
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
|
const socket = net.connect({ host, port });
|
|
|
|
|
const done = (ok) => {
|
|
|
|
|
socket.removeAllListeners();
|
|
|
|
|
socket.destroy();
|
|
|
|
|
resolve(ok);
|
|
|
|
|
};
|
|
|
|
|
socket.setTimeout(2000);
|
|
|
|
|
socket.once("connect", () => done(true));
|
|
|
|
|
socket.once("timeout", () => done(false));
|
|
|
|
|
socket.once("error", () => done(false));
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { host, port } = parsePostgresTarget(databaseUrl);
|
|
|
|
|
console.log(`[db] waiting for Postgres at ${host}:${port}`);
|
|
|
|
|
|
|
|
|
|
for (let i = 1; i <= maxAttempts; i++) {
|
|
|
|
|
if (await canConnect(host, port)) {
|
2026-08-09 22:47:43 +02:00
|
|
|
console.log(`[db] postgres ready (attempt ${i})`);
|
|
|
|
|
process.exit(0);
|
|
|
|
|
}
|
|
|
|
|
process.stdout.write(`[db] waiting for postgres… (${i}/${maxAttempts})\r`);
|
|
|
|
|
await delay(sleepMs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
console.error("\n[db] postgres did not become ready in time");
|
2026-08-10 01:12:21 +02:00
|
|
|
console.error(`Check: DATABASE_URL host ${host}:${port} is up and listening`);
|
|
|
|
|
console.error("Native: sudo systemctl status postgresql");
|
|
|
|
|
console.error("Docker (optional local): docker compose ps && docker compose logs postgres");
|
2026-08-09 22:47:43 +02:00
|
|
|
process.exit(1);
|