CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | /**
* Health + metrics endpoints for load-balancer + observability.
*
* GET /healthz — liveness (always 200 if process alive)
* GET /readyz — readiness (checks DB is reachable)
* GET /metrics — basic in-process counters
*/
import { Hono } from "hono";
import { sql } from "drizzle-orm";
import { db } from "../db";
const health = new Hono();
const started = Date.now();
const counters = {
requests: 0,
errors: 0,
};
// Count every request that reaches any health route
health.use("*", async (c, next) => {
counters.requests++;
await next();
});
health.get("/healthz", (c) => {
return c.json({
ok: true,
uptimeMs: Date.now() - started,
});
});
health.get("/readyz", async (c) => {
try {
await db.execute(sql`SELECT 1`);
return c.json({ ok: true, db: "up" });
} catch (err) {
counters.errors++;
return c.json(
{ ok: false, db: "down", error: (err as Error).message },
503
);
}
});
health.get("/metrics", (c) => {
const mem = process.memoryUsage();
return c.json({
uptimeMs: Date.now() - started,
requests: counters.requests,
errors: counters.errors,
heapUsed: mem.heapUsed,
heapTotal: mem.heapTotal,
rss: mem.rss,
nodeVersion: process.version,
});
});
export default health;
|