spb/datacenterindex
Public
HTML 53.9%
TypeScript 44.5%
JavaScript 0.6%
SQL 0.5%
1/**2 * Minimal HTTP server shared by the worker (`main.ts`) and the standalone scheduler (`scheduler.ts`):3 * GET /healthz → JSON from `health()`; 503 while `ready()` is false (shutting down / not started)4 * GET /metrics → Prometheus text from prom.ts after `beforeScrape()` refreshed the gauges5 * Never throws into the caller; errors become 500 JSON responses.6 */7import { createServer, type Server } from "node:http";8import { renderMetrics } from "./prom.js";910export interface HealthHttpOptions {11 port: number;12 role: string;13 health: () => Promise<Record<string, unknown>>;14 ready: () => boolean;15 /** refresh snapshot gauges (queue depth, budgets…) right before rendering */16 beforeScrape?: () => Promise<void>;17 log?: (msg: string) => void;18 /** extra JSON routes keyed by path prefix ("/trace" matches "/trace/<id>") */19 routes?: Record<string, (url: URL) => Promise<{ status: number; body: unknown }>>;20}2122export function startHealthHttp(o: HealthHttpOptions): Server {23 const log = o.log ?? ((m: string) => console.error(`[${o.role}] ${m}`));24 const server = createServer(async (req, res) => {25 try {26 const url = new URL(req.url ?? "/", "http://localhost");27 if (url.pathname === "/healthz" || url.pathname === "/") {28 const body = await o.health();29 const ok = o.ready();30 res.writeHead(ok ? 200 : 503, { "content-type": "application/json", "cache-control": "no-store" });31 res.end(JSON.stringify({ ok, role: o.role, ...body }, null, 2));32 return;33 }34 if (url.pathname === "/metrics") {35 if (o.beforeScrape) await o.beforeScrape().catch((e: Error) => log(`metrics refresh failed: ${e.message}`));36 res.writeHead(200, { "content-type": "text/plain; version=0.0.4; charset=utf-8", "cache-control": "no-store" });37 res.end(renderMetrics());38 return;39 }40 for (const [prefix, handler] of Object.entries(o.routes ?? {})) {41 if (url.pathname === prefix || url.pathname.startsWith(`${prefix}/`)) {42 const r = await handler(url);43 res.writeHead(r.status, { "content-type": "application/json", "cache-control": "no-store" });44 res.end(JSON.stringify(r.body));45 return;46 }47 }48 res.writeHead(404, { "content-type": "application/json" });49 res.end(JSON.stringify({ error: "not found" }));50 } catch (e) {51 res.writeHead(500, { "content-type": "application/json" });52 res.end(JSON.stringify({ error: (e as Error).message }));53 }54 });55 server.on("error", (e) => log(`http error: ${e.message}`));56 server.listen(o.port, "0.0.0.0", () => log(`http :${o.port} (/healthz, /metrics)`));57 return server;58}59