Skip to content

python.fastapi.missing_health_check

Stability Medium

Detects FastAPI app without /health, /healthz, /ready, or /ping endpoints.

Without health checks:

  • Load balancers can’t route — They don’t know if your service is healthy
  • Kubernetes can’t manage — Pods aren’t restarted when unhealthy
  • Deployments break — New versions get traffic before they’re ready
  • Outages go undetected — Monitoring can’t detect service failures

Health checks are required infrastructure for any production service.

# ❌ Before
from fastapi import FastAPI
app = FastAPI()
@app.get("/api/users")
def get_users():
return users

Kubernetes, AWS ALB, and other infrastructure have no way to know if this service is healthy.

# ✅ After
from fastapi import FastAPI
app = FastAPI()
@app.get("/health")
def health_check():
return {"status": "healthy"}
@app.get("/ready")
def readiness_check():
# Check dependencies
db_healthy = check_database()
cache_healthy = check_cache()
if db_healthy and cache_healthy:
return {"status": "ready"}
return JSONResponse(
status_code=503,
content={"status": "not_ready"}
)
@app.get("/api/users")
def get_users():
return users
  • FastAPI app without any health endpoint
  • Health endpoints that don’t return proper status codes
  • Missing readiness vs liveness distinction

Unfault adds a basic /health endpoint. Enhance it with dependency checks for production.

# Liveness: Is the process running?
# Used by Kubernetes to know when to restart
@app.get("/health")
def liveness():
return {"status": "alive"}
# Readiness: Is the service ready for traffic?
# Used by load balancers for routing decisions
@app.get("/ready")
def readiness():
try:
db.execute("SELECT 1")
redis.ping()
return {"status": "ready"}
except Exception:
return JSONResponse(status_code=503, content={"status": "not_ready"})
# Startup: Has initialization completed?
# Used by Kubernetes to know when liveness should start
@app.get("/startup")
def startup():
if app.state.initialized:
return {"status": "started"}
return JSONResponse(status_code=503, content={"status": "starting"})