This commit is contained in:
2026-08-10 01:12:21 +02:00
parent 8580c996c3
commit 76b586ed85
3 changed files with 293 additions and 67 deletions
+58 -24
View File
@@ -1,36 +1,68 @@
#!/usr/bin/env node
/**
* Wait until docker-compose Postgres is accepting connections.
* Wait until DATABASE_URL Postgres accepts TCP connections.
* Works with native Postgres or Docker-mapped ports (no docker CLI required).
*
* Usage: node scripts/wait-postgres.mjs
*/
import { spawnSync } from "node:child_process";
import net from "node:net";
import { setTimeout as delay } from "node:timers/promises";
import { repoRoot } from "./root-env.mjs";
import { loadRootEnv } from "./root-env.mjs";
const maxAttempts = Number(process.env.DESCRYBE_DB_WAIT_ATTEMPTS || 60);
const sleepMs = Number(process.env.DESCRYBE_DB_WAIT_MS || 1000);
for (let i = 1; i <= maxAttempts; i++) {
const r = spawnSync(
"docker",
[
"compose",
"exec",
"-T",
"postgres",
"pg_isready",
"-U",
"descrybe",
"-d",
"descrybe",
],
{
cwd: repoRoot,
encoding: "utf8",
shell: process.platform === "win32",
},
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)",
);
if (r.status === 0) {
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)) {
console.log(`[db] postgres ready (attempt ${i})`);
process.exit(0);
}
@@ -39,5 +71,7 @@ for (let i = 1; i <= maxAttempts; i++) {
}
console.error("\n[db] postgres did not become ready in time");
console.error("Check: docker compose ps && docker compose logs postgres");
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");
process.exit(1);