diff --git a/apps/hub/src/server.ts b/apps/hub/src/server.ts index 42c8123e..cd2b9e6c 100644 --- a/apps/hub/src/server.ts +++ b/apps/hub/src/server.ts @@ -14,6 +14,8 @@ if (import.meta.main) { const log = getLogger(["corbits-builder", "hub"]); let close = async () => {}; let stopping: Promise | undefined; + let stopRequested = false; + let startupDone = false; const shutDown = async () => { for (const step of [close, dispose]) { try { @@ -28,6 +30,7 @@ if (import.meta.main) { const exitOnFatal = (message: string) => async (error: unknown) => { try { log.error(message, errorMetadata(error)); + // Unlike a signal, this does not wait for startup: a startup stuck on the failure would keep the hub up instead of letting its supervisor restart it. await stop(); } finally { // Handles a failed shutdown left open would keep a broken hub alive instead of letting its supervisor restart it. @@ -39,14 +42,18 @@ if (import.meta.main) { exitOnFatal("Hub hit an unhandled rejection"), ); process.on("uncaughtException", exitOnFatal("Hub hit an uncaught exception")); - process.once("SIGTERM", () => { - void stop(); - }); - process.once("SIGINT", () => { - void stop(); - }); - try { + // Startup takes seconds; a stop meanwhile is recorded and acted on when startup finishes, so it closes what startup opened. + const requestStop = () => { + stopRequested = true; + if (startupDone) void stop(); + }; + process.once("SIGTERM", requestStop); + process.once("SIGINT", requestStop); + const start = async () => { const runtime = await createHubRuntime(); + close = () => runtime.close(); + // A stop requested meanwhile must not open the port; the stop after startup closes the runtime. + if (stopRequested) return; const server = Bun.serve({ hostname: runtime.hostname, port: runtime.port, @@ -63,6 +70,9 @@ if (import.meta.main) { log.info( "Hub ready: Postgres connected; local Interchange sidecar provisioner", ); + }; + try { + await start(); } catch (error) { log.error( "Hub startup failed; check environment and database readiness", @@ -71,4 +81,6 @@ if (import.meta.main) { process.exitCode = 1; await stop(); } + startupDone = true; + if (stopRequested) await stop(); }