On this page
  1. What is the difference between liveness and readiness?
  2. What should a health check actually check?
  3. Where do health checks get used?
  4. Where AI coding assistants get this wrong
  5. Checklist
  6. FAQ
    1. What status code should a health check return?
    2. Should health checks require authentication?
  7. Related topics
  8. Sources
concept

What Is a Health Check?

A health check is an endpoint that reports whether your app is alive and ready. Learn the difference between liveness and readiness and why both matter.

Quick answer

  • A health check is an endpoint (usually /healthz) that reports whether your service is alive and able to serve traffic.
  • Liveness says ‘the process is running’; readiness says ‘it can handle requests right now’.
  • Load balancers and orchestrators use health checks to stop sending traffic to broken instances.

What is the difference between liveness and readiness?

A liveness check asks ‘is the process still alive?’ and restarts the container when it fails. A readiness check asks ‘can this instance accept traffic?’ and removes the instance from rotation when it fails, without restarting it. They answer different questions: a service warming up a cache or waiting on a database is alive but not ready; a deadlocked process is neither.

What should a health check actually check?

Keep it honest but cheap: verify the database connection, any queue connection, and that the process responds — but don’t run expensive operations on every probe. A common pattern is /healthz returning 200 with a tiny JSON body, plus a /readyz that performs quick dependency checks with a short timeout. If a check does heavy work, it becomes a self-inflicted load spike when an orchestrator probes it every few seconds.

# FastAPI example
@app.get("/healthz")
def healthz():
    return {"status": "ok"}

@app.get("/readyz")
def readyz():
    db_ok = db.ping(timeout=1)
    return {"status": "ready" if db_ok else "not ready"}, 200 if db_ok else 503

Where do health checks get used?

Load balancers poll them to remove unhealthy instances from rotation. Kubernetes livenessProbe/readinessProbe runs them inside the container. Managed platforms like Fly.io and Railway use them to restart or reschedule apps. Uptime monitors also hit them from outside — a health check is the natural endpoint for ‘is the site actually up’ alerting.

Where this bites vibecoders

AI assistants rarely generate health check endpoints unless asked, so a vibecoder’s first deploy on a platform with a ‘restart on failure’ toggle finds the toggle doesn’t work — there’s no endpoint to probe. Worse, some assistants generate readiness checks that check nothing real, returning 200 even when the database is down. One honest /readyz endpoint turns a platform’s restart and load-balancing features from decoration into working safety nets.

Where AI coding assistants get this wrong

  • Returning 200 unconditionally from a ‘health’ endpoint, so it proves nothing.
  • Putting heavy work (full queries, external calls) in the probe path, spiking load.
  • Confusing liveness and readiness: restarting a service that just isn’t ready yet.
  • Not adding a health endpoint at all, so platforms and monitors have nothing to probe.

Checklist

  • Expose /healthz (alive) and /readyz (dependencies reachable) endpoints.
  • Keep probes cheap and fast with a short timeout.
  • Wire readiness to the load balancer and liveness to the process supervisor.
  • Point an uptime monitor at the health endpoint for external alerting.

FAQ

What status code should a health check return?

200 when healthy, and a 5xx code (usually 503) when not ready. Monitoring and orchestration tooling keys off status codes, so returning 200 for a broken service defeats the purpose.

Should health checks require authentication?

Generally no — orchestrators and monitors need unauthenticated access to probe. Keep the endpoint read-only and leak nothing sensitive; if your platform requires auth for probes, configure that path explicitly.

Sources

Share: