python 34 lines · 6 steps

Liveness vs readiness health checks in FastAPI

Two endpoints separate whether the process is alive from whether its dependencies are actually reachable.

Explained by highlit
1from fastapi import APIRouter, status
2from fastapi.responses import JSONResponse
3from sqlalchemy import text
4from sqlalchemy.exc import SQLAlchemyError
5from sqlalchemy.ext.asyncio import AsyncSession
6from fastapi import Depends
7 
8from app.db import get_session
9 
10router = APIRouter(tags=["health"])
11 
12 
13@router.get("/health/live", status_code=status.HTTP_200_OK)
14async def liveness() -> dict[str, str]:
15 return {"status": "ok"}
16 
17 
18@router.get("/health/ready")
19async def readiness(session: AsyncSession = Depends(get_session)) -> JSONResponse:
20 checks: dict[str, str] = {}
21 
22 try:
23 await session.execute(text("SELECT 1"))
24 checks["database"] = "ok"
25 except SQLAlchemyError as exc:
26 checks["database"] = f"error: {exc.__class__.__name__}"
27 
28 healthy = all(value == "ok" for value in checks.values())
29 code = status.HTTP_200_OK if healthy else status.HTTP_503_SERVICE_UNAVAILABLE
30 
31 return JSONResponse(
32 status_code=code,
33 content={"status": "ok" if healthy else "degraded", "checks": checks},
34 )
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Liveness answers whether the process runs; readiness answers whether it can serve traffic.
  2. 2Probing dependencies with a cheap query surfaces outages without failing the whole request.
  3. 3Mapping check results to HTTP status codes lets orchestrators route traffic automatically.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Liveness vs readiness health checks in FastAPI — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code