52 lines
1.4 KiB
TypeScript
52 lines
1.4 KiB
TypeScript
import { createServer, type Server } from "node:http";
|
|
import { sql } from "drizzle-orm";
|
|
import { db } from "./db.js";
|
|
import { env } from "./env.js";
|
|
import { logger } from "./logger.js";
|
|
|
|
export type HealthStatus = {
|
|
ok: boolean;
|
|
uptimeSec: number;
|
|
db: "ok" | "error";
|
|
sessions?: Record<string, number>;
|
|
};
|
|
|
|
const started = Date.now();
|
|
let getSessionCounts: () => Record<string, number> = () => ({});
|
|
|
|
export function setSessionCountsProvider(fn: () => Record<string, number>): void {
|
|
getSessionCounts = fn;
|
|
}
|
|
|
|
export async function buildHealth(): Promise<HealthStatus> {
|
|
let dbStatus: "ok" | "error" = "ok";
|
|
try {
|
|
await db.execute(sql`select 1`);
|
|
} catch (err) {
|
|
logger.warn({ err }, "health: db ping failed");
|
|
dbStatus = "error";
|
|
}
|
|
return {
|
|
ok: dbStatus === "ok",
|
|
uptimeSec: Math.round((Date.now() - started) / 1000),
|
|
db: dbStatus,
|
|
sessions: getSessionCounts(),
|
|
};
|
|
}
|
|
|
|
export function startHealthServer(): Server {
|
|
const server = createServer(async (req, res) => {
|
|
if (req.url !== "/health") {
|
|
res.writeHead(404).end("not found");
|
|
return;
|
|
}
|
|
const status = await buildHealth();
|
|
res.writeHead(status.ok ? 200 : 503, { "content-type": "application/json" });
|
|
res.end(JSON.stringify(status));
|
|
});
|
|
server.listen(env.BOT_HEALTH_PORT, () => {
|
|
logger.info({ port: env.BOT_HEALTH_PORT }, "health server listening");
|
|
});
|
|
return server;
|
|
}
|