A Modern Django Health Check for AWS ELB
Published
Years ago I wrote an article about how to handle AWS ELB's health check in Django. I pulled that article a few years ago because I felt it was out of date, yet the URL still gets visited every day. Here is an updated approach to how to handle a health check for Django. (And it should work on any platform.)
Not long after I implemented this approach for Prideraiser, I stumbled on django-health-check by the fine folx at RevSys. It's a great package and I highly recommend it if you need more than a basic check or want a pluggable system to write your own checks. But for Prideraiser I try to use as few dependencies as possible and keep things simple.
The Approach #
The approach is simple. A custom middleware that intercepts a
request with the URL "/health-check/" and returns a 200
response. That's it. The problem we're trying to overcome is that
ELB's health check doesn't set a host header, which causes Django to
raise a 400 error because of the ALLOWED_HOSTS
setting.
By using a middleware and putting it earlier in the stack than
Django's security middleware, we return a response before Django
gets a chance to raise an error.
The Code #
import typing
from django import http
from django.conf import settings
class HealthCheckMiddleware:
def __init__(
self, get_response: typing.Callable[[http.HttpRequest], http.HttpResponse]
):
self.get_response = get_response
def __call__(self, request: http.HttpRequest):
if request.path == getattr(settings, "HEALTH_CHECK_URL", "/health-check/"):
output = {
"status": "🏳️🌈🖤🤎🏳️⚧️⚽️",
"timestamp": datetime.datetime.now().isoformat(),
}
return http.JsonResponse(output)
return self.get_response(request)
This is as basic as I could make it. There's only one setting,
HEALTH_CHECK_URL
, that lets us override what URL to
listen to. The response is a JSON response with a timestamp and a
status message. The status message can be anything you want. We went
with our emoji stack for some fun.
Here's what our MIDDLEWARE
setting looks like:
MIDDLEWARE = [
"prideraiser.middleware.health_check.HealthCheckMiddleware",
"django.middleware.security.SecurityMiddleware",
# other middleware
]
That's all there is to it. Now you've got a simple way to return a health check in Django no matter what the host.