Serve mode waits for its broker instead of crash-looping (issue 058)

At startup 'the broker is not reachable yet' is the normal case — a
container comes up in seconds, the overlay tunnel a moment later.
Exiting delegated the retry to the container runtime, which read as a
crash-loop to every restart-counting health check and every person
watching docker ps. Serve mode now retries with capped backoff, aloud,
indefinitely; a pinned-certificate mismatch still refuses at once, and
one-shot commands (emit, invoke, run) still fail fast.
This commit is contained in:
2026-09-18 02:06:53 +02:00
parent a99b0d3029
commit 1a55e8f205
+25 -1
View File
@@ -66,13 +66,37 @@ async function connectBroker(): Promise<Broker> {
return connectAmqp(url);
}
/**
* Connect for serve mode, retrying while the broker is merely not reachable yet. At startup that
* is the NORMAL case, not a failure: a container comes up in seconds and the overlay tunnel a
* moment later (novox/hq issue 058). Exiting instead delegated the retry to the container
* runtime, which read as a crash-loop to every restart-counting health check and every person
* watching. Retried indefinitely, aloud: the dependency appears or somebody reads why not.
*
* Only reachability retries. A pinned-certificate mismatch is a refusal, not a wait — an
* impostor does not become the broker by being asked again — and configuration errors already
* exit inside connectBroker before anything is thrown here.
*/
async function connectBrokerPatiently(): Promise<Broker> {
for (let delay = 2_000; ; delay = Math.min(delay * 2, 30_000)) {
try {
return await connectBroker();
} catch (err) {
const why = err instanceof Error ? err.message : String(err);
if (why.includes("does not match the pinned")) throw err;
console.error(`mesh-tools: the broker is not reachable yet (${why}); retrying in ${delay / 1000}s`);
await new Promise((r) => setTimeout(r, delay));
}
}
}
async function serve(): Promise<void> {
const moduleEntrypoints = (process.env.MESH_TOOL_MODULES ?? "")
.split(",")
.map((s) => s.trim())
.filter(Boolean);
const broker = await connectBroker();
const broker = await connectBrokerPatiently();
const stop = await runTools({ broker, moduleEntrypoints });
const shutdown = async (): Promise<void> => {