FastAPI cookbook · Beginner
Add liveness and readiness endpoints to FastAPI
Tell Kubernetes or a load balancer when an instance is alive and ready to receive traffic.
Approach
/healthz returns 200 if the process is responsive (no dependency checks). /readyz checks critical dependencies (database, Redis) with short timeouts and returns 503 if any fail. Exclude both from auth, docs and noisy access logs.
Solution
import asyncio
from fastapi import APIRouter, Response
from sqlalchemy import text
health = APIRouter(include_in_schema=False)
@health.get("/healthz")
async def liveness() -> dict:
return {"status": "ok"}
@health.get("/readyz")
async def readiness(response: Response) -> dict:
async def check_db():
async with engine.connect() as conn:
await conn.execute(text("SELECT 1"))
async def check_redis():
await redis.ping()
results = {}
for name, check in {"database": check_db, "redis": check_redis}.items():
try:
await asyncio.wait_for(check(), timeout=1.5)
results[name] = "ok"
except Exception:
results[name] = "fail"
ready = all(v == "ok" for v in results.values())
response.status_code = 200 if ready else 503
return {"status": "ready" if ready else "not_ready", "checks": results}
app.include_router(health)
Pitfalls
- Liveness that checks the database (restart storms during DB incidents).
- Readiness without timeouts.
- Exposing detailed error messages publicly.
Variations
- Report ready=false during graceful shutdown so the load balancer drains traffic first.
Further reading: Kubernetes: Configure probes
More FastAPI recipes
- Add OpenTelemetry tracing to FastAPI
- Add request IDs and structured logs to FastAPI
- Build a WebSocket chat endpoint in FastAPI
- Cache FastAPI responses in Redis
- Call external APIs with retries and timeouts from FastAPI
- Implement role-based access control in FastAPI
- Isolate tenants in a multi-tenant FastAPI app
- Paginate with cursors in FastAPI