On this page
  1. What endpoints do I add?
  2. How do I wire it to Docker?
  3. What does ‘it worked’ look like?
  4. Where AI coding assistants get this wrong
  5. Checklist
  6. FAQ
    1. How often should probes run?
    2. My app takes 20 seconds to start; will it be restarted in a loop?
  7. Related topics
  8. Sources
tutorial

How to Add Health Checks to Your App

Add liveness and readiness endpoints to a Python, Node, or Go app and wire them to your platform so failures trigger restarts and routing.

Quick answer

  • Add /healthz (process alive) and /readyz (dependencies reachable) endpoints to your app.
  • Use a Docker HEALTHCHECK or your platform’s probe config to consume them.
  • Test that a failed dependency actually returns a non-200 so the probe is honest.

What endpoints do I add?

Two: /healthz returns 200 as long as the process responds, and /readyz returns 200 only when the dependencies it needs (database, cache, queue) are reachable, 503 otherwise. Keep both fast — a 1-second timeout on dependency checks. The framework snippets below show the minimal shape.

# FastAPI / Flask-style
@app.get("/readyz")
def readyz():
    try:
        db.session.execute(text("SELECT 1"))
        return {"status": "ready"}
    except Exception:
        return JSONResponse({"status": "not ready"}, status_code=503)

How do I wire it to Docker?

Add a HEALTHCHECK instruction to the Dockerfile so Docker (and platforms that read it) can probe the container. Use curl or a tiny script; check both that the endpoint responds and that readiness is true. Platforms like Railway and Fly.io also let you define a probe URL in config, which is often easier than relying on HEALTHCHECK alone.

FROM python:3.13-slim
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
  CMD python -c "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://localhost:8000/readyz', timeout=2).status==200 else 1)"
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]

What does ‘it worked’ look like?

Stop the database and curl /readyz — it should return 503 within a second or two. Restart the database and it returns 200. In the platform dashboard, the container shows healthy, and if you kill the process the platform restarts it. If a probe returns 200 while the database is down, the check is not checking anything real — fix that before relying on it.

Where this bites vibecoders

This is a small, concrete task where AI assistants shine but still need supervision: they’ll happily write the endpoints, but may return 200 unconditionally, probe an external service (defeating the point), or set a start-period too short so the app gets restarted while still booting. The test at the end — break the database, watch the probe go 503 — is the part that catches those mistakes.

Where AI coding assistants get this wrong

  • Health endpoint that always returns 200 regardless of actual state.
  • Readiness check that probes an external API instead of the app’s own dependencies.
  • HEALTHCHECK with no start-period, restarting a slow-booting app forever.
  • Probe hitting an endpoint that itself does expensive work, spiking load.

Checklist

  • Add /healthz and /readyz with cheap, real checks.
  • Return 503 (not 200) when dependencies are unreachable.
  • Configure HEALTHCHECK or platform probes with a start-period.
  • Verify by breaking a dependency and watching the probe flip.

FAQ

How often should probes run?

Every 10-30 seconds is typical. Frequent probes catch failures faster but add load; every probe should be a cheap operation with a short timeout so the interval doesn’t matter much.

My app takes 20 seconds to start; will it be restarted in a loop?

Only if you misconfigure the start-period. Set the start-period (or initial delay) to longer than your slowest startup so the platform gives the app time to boot before counting failures.

Sources

Share: