phase11: /health/live + /health/ready endpoints + monitoring docs + Prometheus metrics docs
This commit is contained in:
+56
-2
@@ -1,8 +1,14 @@
|
||||
"""Health check endpoint — extended with DB, Redis, storage, worker checks."""
|
||||
"""Health check endpoints — liveness, readiness, and full health.
|
||||
|
||||
/health/live — process is alive (always 200 if running)
|
||||
/health/ready — ready to serve requests (checks DB, Redis, storage)
|
||||
/api/v1/health — full health with all checks (backward compatible)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter
|
||||
from pydantic import BaseModel
|
||||
|
||||
from app.core.monitoring import get_health_status
|
||||
from app.schemas.common import HealthResponse
|
||||
@@ -10,9 +16,57 @@ from app.schemas.common import HealthResponse
|
||||
router = APIRouter(tags=["health"])
|
||||
|
||||
|
||||
class LiveResponse(BaseModel):
|
||||
status: str = "alive"
|
||||
|
||||
|
||||
class ReadyResponse(BaseModel):
|
||||
status: str # "ready" or "not_ready"
|
||||
checks: dict[str, str] = {}
|
||||
|
||||
|
||||
@router.get("/health/live")
|
||||
async def health_live() -> LiveResponse:
|
||||
"""Liveness probe — process is alive.
|
||||
|
||||
Returns 200 if the process is running.
|
||||
Used by Kubernetes/Coolify for restart decisions.
|
||||
"""
|
||||
return LiveResponse(status="alive")
|
||||
|
||||
|
||||
@router.get("/health/ready")
|
||||
async def health_ready() -> ReadyResponse:
|
||||
"""Readiness probe — ready to serve requests.
|
||||
|
||||
Checks:
|
||||
- PostgreSQL connection
|
||||
- Redis connection
|
||||
- Storage backend
|
||||
- Worker heartbeat (if available)
|
||||
|
||||
Returns 200 if all checks pass, 503 if any fail.
|
||||
Used by load balancer to route traffic.
|
||||
"""
|
||||
health = await get_health_status()
|
||||
checks = {}
|
||||
all_ready = True
|
||||
|
||||
for check_name, check_val in (health.checks or {}).items():
|
||||
status = "ok" if check_val == "ok" or check_val is True else "fail"
|
||||
checks[check_name] = status
|
||||
if status != "ok":
|
||||
all_ready = False
|
||||
|
||||
return ReadyResponse(
|
||||
status="ready" if all_ready else "not_ready",
|
||||
checks=checks,
|
||||
)
|
||||
|
||||
|
||||
@router.get("/api/v1/health", response_model=HealthResponse)
|
||||
async def health():
|
||||
"""Health check — no auth required.
|
||||
"""Full health check — no auth required.
|
||||
|
||||
Returns status (healthy/degraded) and individual checks for
|
||||
database, redis, storage, and worker.
|
||||
|
||||
Reference in New Issue
Block a user