feat(ops): web + worker container healthchecks (#20)
docker-compose only health-checked db. Add: - web: an unauthenticated GET /api/health (excluded from the auth middleware) + a compose healthcheck that hits it (node global fetch — no curl/wget in image). - worker: a background daemon thread touches /tmp/worker.alive every ~15s (independent of the main loop, so it stays fresh through a long download) + a compose healthcheck on the file's mtime (unhealthy if >90s stale). Now `docker compose ps` reports real health for all services. worker 223 tests, web 154, tsc + build + compose config clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { GET } from "./route";
|
||||
|
||||
describe("GET /api/health", () => {
|
||||
it("returns 200 ok", async () => {
|
||||
const res = GET();
|
||||
expect(res.status).toBe(200);
|
||||
expect(await res.json()).toEqual({ ok: true });
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,5 @@
|
||||
// Unauthenticated liveness endpoint for the docker-compose healthcheck. Excluded from the
|
||||
// auth gate in middleware.ts.
|
||||
export function GET() {
|
||||
return Response.json({ ok: true });
|
||||
}
|
||||
@@ -8,7 +8,10 @@ export async function middleware(req: NextRequest) {
|
||||
if (!token) return NextResponse.next(); // auth disabled (no LYRA_PASSWORD)
|
||||
|
||||
const { pathname } = req.nextUrl;
|
||||
if (pathname === "/login" || pathname === "/api/auth") return NextResponse.next();
|
||||
// /api/health is the unauthenticated liveness probe for the compose healthcheck.
|
||||
if (pathname === "/login" || pathname === "/api/auth" || pathname === "/api/health") {
|
||||
return NextResponse.next();
|
||||
}
|
||||
|
||||
const cookie = req.cookies.get(AUTH_COOKIE)?.value ?? "";
|
||||
if (safeEqual(cookie, token)) return NextResponse.next();
|
||||
|
||||
Reference in New Issue
Block a user