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"})
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
]
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
)
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"})
Register the monitor in Vigilmon
- Sign up at vigilmon.online — free, no card required
- Click Add Monitor → HTTP Check
- Enter your URL:
https://yourdomain.com/health/ - Set check interval: 1 minute
- 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:
- You create a heartbeat monitor in Vigilmon with an expected interval (e.g., every 10 minutes)
- At the end of each successful Celery task run, your code pings Vigilmon's URL
- 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:
- Click Add Monitor → Heartbeat
- Name it (e.g., "Send email digests")
- Set the expected interval to match your task schedule
- 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
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
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")
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)
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
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
- Go to Settings → Integrations → Slack
- Click Connect to Slack and authorize the app
- Choose a channel (e.g.,
#incidentsor#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)