← back to Homesonspec

apps/workers/src/health-server.ts

58 lines

import http from "node:http";

export interface HealthVerdict {
  healthy: boolean;
  reason: string;
}

/**
 * Auxiliary liveness probe for the worker.
 *
 * CRITICAL (TK-10240 prod incident 2026-08-09): a bind failure here — e.g.
 * EADDRINUSE when the chosen port is already taken on the shared Kamatera host,
 * which crash-looped the worker on the first prod deploy — must NEVER crash the
 * worker. The probe is AUXILIARY; the worker keeps draining the queue. Without a
 * `.on('error')` handler the emitted 'error' event is unhandled → uncaughtException
 * → process abort → pm2 crash-loop: the exact failure mode this ticket set out to
 * eliminate, reintroduced through the probe. So we log and continue instead.
 *
 * Binds 127.0.0.1 by default so the probe is local-only (pm2 / monitoring on the
 * box), never publicly exposed.
 */
export function startHealthServer(opts: {
  port: number;
  host?: string;
  health: () => HealthVerdict;
  log?: (...args: unknown[]) => void;
  errorLog?: (...args: unknown[]) => void;
}): http.Server {
  const host = opts.host ?? "127.0.0.1";
  const log = opts.log ?? ((...a: unknown[]) => console.log(...a));
  const errorLog = opts.errorLog ?? ((...a: unknown[]) => console.error(...a));

  const server = http.createServer((req, res) => {
    if (req.url === "/health") {
      const verdict = opts.health();
      res.writeHead(verdict.healthy ? 200 : 503, { "content-type": "application/json" });
      res.end(JSON.stringify(verdict));
      return;
    }
    res.writeHead(404);
    res.end();
  });

  // Non-fatal: a probe that can't bind must not take the worker down with it.
  server.on("error", (err) => {
    const code = (err as NodeJS.ErrnoException).code ?? String(err);
    errorLog(`workers: health endpoint failed to bind ${host}:${opts.port} (${code}); continuing without it`);
  });

  server.listen(opts.port, host, () => log(`workers: health endpoint on ${host}:${opts.port}/health`));
  return server;
}

/** Close a health server only if it actually bound (close() on a non-listening server throws). */
export function closeHealthServer(server: http.Server): void {
  if (server.listening) server.close();
}