Skip to content

Health checks

Path Use Checks Auth
/up Container health check (Kamal, see deploy/config/deploy.yml), ALB targets None: Django is serving requests None
/export/up Uptime monitor for the pool that serves the /export/ API None: same view as /up None
/status/ Status page / uptime monitor Every database, the cache, Redis (Celery broker) Token
/status/celery/ Status page / uptime monitor A Celery worker answers a ping and consumes every queue Token

/up and /export/up touch no database or other service, so an outage elsewhere does not get healthy containers restarted or pulled out of the load balancer. The view opts out of ATOMIC_REQUESTS, which would otherwise open a database connection for every request.

/export/up exists only for its URL: the load balancer sends /export/* to its own hosts, so a monitor that polls it through the public hostname learns whether that pool is serving. The load balancer's own target health checks go straight to each host and should use /up.

/status/ URLs return 200 when every check passes and 500 when any fails, with one line per check. Pick the format with ?format=json or ?format=text, or the Accept header. /status/ leaves out Celery so the web tier is not reported down because workers are.

When HEALTH_CHECK_TOKENS (comma-separated) is set, /status/ URLs need one of those tokens, either in an Authorization: Bearer <token> header (preferred: it keeps the token out of URLs and access logs) or as ?token=<token>. A missing or wrong token gets a 404. /up and /export/up are never protected. When the setting is unset, as in local development, /status/ is open.

None of these paths are traced in Sentry (commcare_connect/utils/sentry.py). A failing /status/ check is still a 500, so Django logs it and Sentry records an error.

The checks are defined in checks.py, built on django-health-check.