DEV Community

Vigilmon
Vigilmon

Posted on

How to monitor your Django app with uptime checks and heartbeat monitoring (free)

Your Django app is running fine. Or is it?

Your Celery task stopped processing the queue 3 hours ago. Your /api/products/ endpoint is returning 500s. Your SSL certificate expires in 4 days. Do you know about any of this?

Most Python developers discover downtime through support tickets, not monitoring. By then, users have already churned.

In this tutorial, you will add free uptime monitoring to your Django app using Vigilmon in under 10 minutes. We will cover:

  • HTTP uptime checks for your Django REST endpoints
  • Heartbeat monitoring for Django management commands and Celery tasks
  • SSL certificate expiry alerts
  • Slack and email notifications

No credit card required.


1. The Problem: Django's Silent Failure Modes

Django apps fail in two distinct ways:

Loud failures — an unhandled exception, a 500 page, a traceback in your logs. These are annoying but visible.

Silent failures — the ones that kill trust:

  • A Celery worker crashes and tasks pile up invisibly in the queue
  • A management command (send_digests, sync_inventory) stops running without error
  • Your PostgreSQL connection pool exhausts itself and queries start timing out
  • Your SSL cert expires and browsers show "connection not secure"

Django's own error logging won't catch these. You need external monitoring that checks from outside your infrastructure.


2. What Vigilmon Does

Vigilmon provides three types of monitoring that map directly onto Django's failure modes:

HTTP Checks — Vigilmon pings your endpoints every minute and alerts you if they return non-2xx status codes or slow responses. Works for Django REST Framework, Django views, and DRF viewsets.

Heartbeat Monitoring — Your Celery task or management command pings Vigilmon after each successful run. If Vigilmon does not receive a ping within the expected window, it alerts you. This is the only reliable way to catch silent task failures.

SSL Expiry — Vigilmon warns you 30, 14, and 7 days before your SSL certificate expires, so you are never surprised.

All of this is free on the free tier. No credit card needed.


3. Add a Health Check Endpoint to Django

The first step is giving Vigilmon something reliable to ping. Add a /health/ endpoint that does not require authentication.

Basic health check

# views.py
from django.http import JsonResponse
from django.views import View

class HealthCheckView(View):
    def get(self, request):
        return JsonResponse({"status": "ok"})
Enter fullscreen mode Exit fullscreen mode

Wire it up in urls.py:

# urls.py
from django.urls import path
from .views import HealthCheckView

urlpatterns = [
    path("health/", HealthCheckView.as_view(), name="health-check"),
    # ... your other urls
]
Enter fullscreen mode Exit fullscreen mode

Health check with database connectivity

For production, you want to verify the database is reachable too:

# views.py
from django.http import JsonResponse
from django.db import connection
from django.views import View

class HealthCheckView(View):
    def get(self, request):
        try:
            with connection.cursor() as cursor:
                cursor.execute("SELECT 1")
            return JsonResponse({"status": "ok", "db": "connected"})
        except Exception as e:
            return JsonResponse(
                {"status": "error", "db": "disconnected"},
                status=503
            )
Enter fullscreen mode Exit fullscreen mode

Using Django REST Framework

If you are using DRF, keep it simple with an APIView:

# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import AllowAny

class HealthCheckView(APIView):
    permission_classes = [AllowAny]

    def get(self, request):
        return Response({"status": "ok"})
Enter fullscreen mode Exit fullscreen mode

Register the monitor in Vigilmon

  1. Sign up at vigilmon.online — free, no card required
  2. Click Add Monitor → HTTP Check
  3. Enter your URL: https://yourdomain.com/health/
  4. Set check interval: 1 minute
  5. Alert condition: status not 2xx, or response time > 3000ms

Vigilmon starts pinging immediately and alerts you within a minute of downtime.


4. Heartbeat Monitoring for Celery Tasks

This is the most important monitoring for Django apps. Celery workers crash silently — the queue fills up, no emails go out, no data syncs, and you find out from a user complaint days later.

Here is how heartbeat monitoring works:

  1. You create a heartbeat monitor in Vigilmon with an expected interval (e.g., every 10 minutes)
  2. At the end of each successful Celery task run, your code pings Vigilmon's URL
  3. If Vigilmon does not receive a ping within the interval plus a grace period, it fires an alert

Setting up the heartbeat monitor

In Vigilmon:

  1. Click Add Monitor → Heartbeat
  2. Name it (e.g., "Send email digests")
  3. Set the expected interval to match your task schedule
  4. Copy the ping URL — it looks like https://vigilmon.online/api/heartbeat/ping/abc123?utm_source=devto&utm_medium=article&utm_campaign=content

Store it in your .env:

VIGILMON_EMAIL_DIGEST_HEARTBEAT=https://vigilmon.online/api/heartbeat/ping/YOUR_ID_HERE?utm_source=devto&utm_medium=article&utm_campaign=content
Enter fullscreen mode Exit fullscreen mode

Wiring it into a Celery task

# tasks.py
import os
import requests
from celery import shared_task
import logging

logger = logging.getLogger(__name__)

VIGILMON_HEARTBEAT_URL = os.environ.get("VIGILMON_EMAIL_DIGEST_HEARTBEAT")

def ping_vigilmon(heartbeat_url):
    """Send heartbeat to Vigilmon. Failures are non-fatal."""
    if not heartbeat_url:
        return
    try:
        requests.get(heartbeat_url, timeout=5)
    except Exception as e:
        logger.warning(f"Vigilmon heartbeat failed: {e}")

@shared_task
def send_email_digests():
    try:
        # Your actual task logic
        users = User.objects.filter(digest_enabled=True)
        for user in users:
            send_digest_email(user)

        # Only ping after successful completion
        ping_vigilmon(VIGILMON_HEARTBEAT_URL)
        logger.info("Email digests sent, heartbeat pinged")
    except Exception as e:
        logger.error(f"Email digest task failed: {e}")
        raise  # Re-raise so Celery marks the task as failed
        # No ping = Vigilmon alerts after the grace period
Enter fullscreen mode Exit fullscreen mode

The key principle: only ping after the task succeeds. If an exception is raised, skip the ping. Vigilmon sees the missed heartbeat and fires an alert.

Monitoring multiple Celery tasks

Create a separate heartbeat monitor per task — this gives you per-task failure visibility:

# tasks.py
import os
import requests

HEARTBEATS = {
    "email_digests": os.environ.get("VIGILMON_EMAIL_DIGESTS_HEARTBEAT"),
    "inventory_sync": os.environ.get("VIGILMON_INVENTORY_SYNC_HEARTBEAT"),
    "report_generation": os.environ.get("VIGILMON_REPORTS_HEARTBEAT"),
}

def ping_vigilmon(key):
    url = HEARTBEATS.get(key)
    if url:
        try:
            requests.get(url, timeout=5)
        except Exception:
            pass  # Non-fatal

@shared_task
def sync_inventory():
    # ... task logic ...
    ping_vigilmon("inventory_sync")

@shared_task
def generate_weekly_report():
    # ... task logic ...
    ping_vigilmon("report_generation")
Enter fullscreen mode Exit fullscreen mode

5. Heartbeat Monitoring for Django Management Commands

Management commands are even more likely to fail silently than Celery tasks because they are often run from cron and cron failures produce no alerts.

# management/commands/sync_products.py
import os
import requests
from django.core.management.base import BaseCommand

class Command(BaseCommand):
    help = "Sync products from external API"

    def handle(self, *args, **options):
        try:
            self.stdout.write("Syncing products...")
            # Your sync logic here
            synced_count = sync_products_from_api()
            self.stdout.write(
                self.style.SUCCESS(f"Synced {synced_count} products")
            )

            # Ping Vigilmon only on success
            heartbeat_url = os.environ.get("VIGILMON_PRODUCT_SYNC_HEARTBEAT")
            if heartbeat_url:
                requests.get(heartbeat_url, timeout=5)

        except Exception as e:
            self.stderr.write(self.style.ERROR(f"Sync failed: {e}"))
            raise SystemExit(1)
Enter fullscreen mode Exit fullscreen mode

Your cron entry in /etc/cron.d/django:

*/15 * * * * www-data /path/to/venv/bin/python /path/to/manage.py sync_products >> /var/log/django/sync.log 2>&1
Enter fullscreen mode Exit fullscreen mode

Set the heartbeat interval in Vigilmon to 15 minutes (matching your cron schedule). If the command fails or cron itself stops running, Vigilmon alerts you within one missed interval.


6. Configure Slack and Email Alerts

Email alerts

Vigilmon sends alerts to your account email by default. You can add extra recipients (on-call engineer, your team inbox) under Settings → Notifications.

Slack alerts

  1. Go to Settings → Integrations → Slack
  2. Click Connect to Slack and authorize the app
  3. Choose a channel (e.g., #incidents or #backend-alerts)

When your Django API goes down or a Celery task misses its heartbeat, Slack gets a message within the minute. The alert includes the monitor name, failure type, timestamp, and a direct link to investigate.

Recovery notifications are sent automatically — no manual "all clear" needed.


7. Optional: Public Status Page

If your Django app serves external customers, a public status page lets them check uptime themselves instead of filing support tickets.

Go to Settings → Status Page, enable it, and Vigilmon generates a public URL showing:

  • Live status of all your monitors
  • Uptime percentages over the last 30 and 90 days
  • Incident history with timestamps

It automatically reflects whatever monitors you have configured — no extra setup.


Recap

Here is what you have in place after following this guide:

Scenario What happens
Django API returns 500s or goes offline HTTP monitor alerts within 1 minute
Celery task stops running silently Heartbeat monitor alerts after missed ping
Management command cron stops firing Heartbeat monitor alerts after missed ping
SSL cert approaching expiry 30/14/7-day advance warnings
Alert fires Instant Slack message + email
Users want to check uptime Public status page URL

Free tier includes:

  • Up to 10 monitors
  • 1-minute check intervals
  • Email and Slack notifications
  • Public status page
  • No credit card required

Get started at vigilmon.online — setup takes less time than it took to read this article.


Also worth reading: Monitor your Node.js app with Vigilmon

Top comments (0)