"""Liveness and readiness endpoints. ``/health/live`` answers whether the process is up. ``/health/ready`` answers whether it can serve: the database is reachable and configured correctly (WAL, foreign keys). Tests and any future orchestration wait on readiness rather than a sleep. Readiness returns 503 until the checks pass. """ from __future__ import annotations from fastapi import APIRouter, Request, Response from sqlalchemy import text router = APIRouter(tags=["health"]) @router.get("/health/live") def live() -> dict: return {"status": "alive"} @router.get("/health/ready") def ready(request: Request, response: Response) -> dict: checks: dict[str, object] = {} ok = True engine = getattr(request.app.state, "engine", None) if engine is None: ok = False checks["database"] = "unavailable" else: try: with engine.connect() as conn: conn.execute(text("SELECT 1")) journal_mode = conn.execute(text("PRAGMA journal_mode")).scalar() foreign_keys = conn.execute(text("PRAGMA foreign_keys")).scalar() checks["database"] = "ok" checks["journal_mode"] = journal_mode checks["foreign_keys"] = int(foreign_keys) if str(journal_mode).lower() != "wal" or int(foreign_keys) != 1: ok = False except Exception: ok = False checks["database"] = "error" response.status_code = 200 if ok else 503 return {"status": "ready" if ok else "not_ready", "checks": checks}