Usage
Setting up monitoring
You can point an uptime monitor such as Pingdom, StatusCake, or other
uptime robots at your service. The /health/ endpoint returns an HTTP
200 when every check passes, and an HTTP 500 when any of them fails.
For step-by-step examples of multi-tier endpoint setups, including uptime monitoring, container probes, reverse-proxy configuration, and RSS/Atom integration into Slack or Matrix, see the Cookbook.
Getting machine-readable reports
Plain text
For simple monitoring and scripting, ask for plain text. Set the Accept HTTP header to text/plain, or pass format=text as a query parameter.
When everything passes, you get a plain text response with HTTP 200. When a check fails, you get HTTP 500:
$ curl -v -X GET -H "Accept: text/plain" http://www.example.com/health/
> GET /health/ HTTP/1.1
> Host: www.example.com
> Accept: text/plain
>
< HTTP/1.1 200 OK
< Content-Type: text/plain; charset=utf-8
CacheBackend: OK
DatabaseBackend: OK
S3BotoStorageHealthCheck: OK
$ curl -v -X GET http://www.example.com/health/?format=text
> GET /health/?format=text HTTP/1.1
> Host: www.example.com
>
< HTTP/1.1 200 OK
< Content-Type: text/plain; charset=utf-8
CacheBackend: OK
DatabaseBackend: OK
S3BotoStorageHealthCheck: OK
This format is handy for command-line tools and simple scripts that don't want to parse JSON.
JSON
Want machine-readable results? Set the Accept HTTP header to
application/json, or pass format=json as a query parameter.
The endpoint returns a JSON response:
$ curl -v -X GET -H "Accept: application/json" http://www.example.com/health/
> GET /health/ HTTP/1.1
> Host: www.example.com
> Accept: application/json
>
< HTTP/1.1 200 OK
< Content-Type: application/json
{
"CacheBackend": "working",
"DatabaseBackend": "working",
"S3BotoStorageHealthCheck": "working"
}
$ curl -v -X GET http://www.example.com/health/?format=json
> GET /health/?format=json HTTP/1.1
> Host: www.example.com
>
< HTTP/1.1 200 OK
< Content-Type: application/json
{
"CacheBackend": "working",
"DatabaseBackend": "working",
"S3BotoStorageHealthCheck": "working"
}
OpenMetrics for Prometheus
If you monitor with Prometheus, request the OpenMetrics format:
$ curl http://www.example.com/health/?format=openmetrics
Prometheus can scrape these metrics directly.
RSS and Atom feeds
For feed readers and monitoring tools, request the RSS or Atom format:
$ curl http://www.example.com/health/?format=rss
$ curl http://www.example.com/health/?format=atom
You can also use the Accept header:
$ curl -H "Accept: application/rss+xml" http://www.example.com/health/
$ curl -H "Accept: application/atom+xml" http://www.example.com/health/
These endpoints always answer with HTTP 200. The feed lists each check, and failed checks show up as categories and item descriptions.
Writing a custom health check
You can write your own checks too. Inherit from
HealthCheck and implement the run method.
health_check.HealthCheck
dataclass
Bases: ABC
Base class for defining health checks.
Subclasses should implement the run method to perform the actual health check logic.
The run method can be either synchronous or asynchronous.
Examples:
>>> import dataclasses
>>> from health_check.base import HealthCheck
>>>
>>> @dataclasses.dataclass
>>> class MyHealthCheck(HealthCheck):
...
... async def run(self):
... # Implement health check logic here
Subclasses should be dataclasses or implement their own __repr__ method
to provide meaningful representations in health check reports.
Warning
The __repr__ method is used in health check reports.
Consider setting repr=False for sensitive dataclass fields
to avoid leaking sensitive information or credentials.
Source code in health_check/base.py
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | |
labels
property
Return a human-readable label for the check, defaulting to the class name.
pretty_status()
Return a human-readable status string, always 'OK' for the check itself.
Source code in health_check/base.py
73 74 75 | |
run()
abstractmethod
async
Run the health check logic and raise human-readable exceptions as needed.
Exception must be reraised to indicate the health status and provide context. Any unexpected exceptions will be caught and logged for security purposes while returning a generic error message.
Warning
Exception messages must not contain sensitive information.
Raises:
| Type | Description |
|---|---|
ServiceWarning
|
If the service is at a critical state but still operational. |
ServiceUnavailable
|
If the service is not operational. |
ServiceReturnedUnexpectedResult
|
If the check performs a computation that returns an unexpected result. |
Source code in health_check/base.py
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | |
Django command
Run the Django command health_check from the shell, or schedule it
with cron:
django-admin health_check health_check
The endpoint argument is the name of the health check URL pattern defined in your
urls.py (see the installation guide). The command looks it up with
reverse() and runs the checks over HTTP against the running server:
Database ... OK
CustomHealthCheck ... Unavailable: Something went wrong!
Pass --no-http to skip the HTTP server entirely. Handy for container
health checks that don't run a web server:
django-admin health_check health_check --no-http
A critical error exits the command with the code 1.
Performance tweaks
Every check runs asynchronously, via asyncio or a thread pool, depending
on how each check is implemented.
IO-bound checks run in parallel, so responses come back faster.
Synchronous checks (for example Database, Mail,
or Storage) run in the event loop's default thread pool.
That pool usually persists between requests. It keeps things fast, but it can
grow memory usage. That's a problem for some applications, especially S3Storage,
which uses thread-local connections.
To avoid that, use a custom executor that spins up a fresh thread pool per
request and tears it down when the checks finish. Subclass HealthCheckView
and override the get_executor method to return a context manager with a
new ThreadPoolExecutor each time.
from concurrent.futures import ThreadPoolExecutor
from health_check.views import HealthCheckView
class CustomHealthCheckView(HealthCheckView):
def get_executor(self):
return ThreadPoolExecutor(max_workers=len(self.checks))
This gives every request its own thread pool. You keep the speed of concurrent execution for synchronous checks, but the memory stays under control.