feat(deploy): add /api/health endpoint for container liveness probes
This commit is contained in:
parent
f915635cf5
commit
91c5a8f625
1 changed files with 63 additions and 0 deletions
63
src/app/api/health/route.ts
Normal file
63
src/app/api/health/route.ts
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
import { existsSync, readFileSync } from "node:fs";
|
||||||
|
import path from "node:path";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lightweight liveness probe for Docker/Coolify healthchecks.
|
||||||
|
* Returns 200 as soon as the Next.js Route Handler layer is up and able to
|
||||||
|
* serve a request. We deliberately DO NOT touch the database here: a transient
|
||||||
|
* DB hiccup should not make Coolify mark the container unhealthy and force a
|
||||||
|
* restart (which would break in-flight requests against an otherwise healthy
|
||||||
|
* web process). DB health is tracked separately by the Coolify-managed
|
||||||
|
* PostgreSQL service.
|
||||||
|
*
|
||||||
|
* Path: GET /api/health
|
||||||
|
*/
|
||||||
|
export const dynamic = "force-dynamic";
|
||||||
|
export const runtime = "nodejs";
|
||||||
|
|
||||||
|
const startedAt = Date.now();
|
||||||
|
|
||||||
|
const HEADERS = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Cache-Control": "no-store, no-transform",
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
type VersionInfo = {
|
||||||
|
version: string | null;
|
||||||
|
tag: string | null;
|
||||||
|
gitDescribe: string | null;
|
||||||
|
commitHash: string | null;
|
||||||
|
commitDate: string | null;
|
||||||
|
commitSubject: string | null;
|
||||||
|
buildTime: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
function readVersionInfo(): Partial<VersionInfo> {
|
||||||
|
const versionInfoPath = path.join(
|
||||||
|
process.cwd(),
|
||||||
|
"src",
|
||||||
|
"generated",
|
||||||
|
"versionInfo.json",
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
if (!existsSync(versionInfoPath)) return {};
|
||||||
|
const raw = readFileSync(versionInfoPath, "utf8");
|
||||||
|
return JSON.parse(raw) as Partial<VersionInfo>;
|
||||||
|
} catch {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function GET(): Promise<Response> {
|
||||||
|
const version = readVersionInfo();
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
ok: true,
|
||||||
|
uptime: Math.max(0, Math.round((Date.now() - startedAt) / 1000)),
|
||||||
|
version: version.version ?? null,
|
||||||
|
commit: version.commitHash ?? null,
|
||||||
|
buildTime: version.buildTime ?? null,
|
||||||
|
}),
|
||||||
|
{ status: 200, headers: HEADERS },
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue