How to monitor a Django management command run on a schedule
Django has no built-in scheduler, so a management command run on a schedule is driven by an external trigger — a UNIX crontab, a Celery beat task, or a platform cron. Monitoring works by having the command signal success to an external monitor as its final action. The command's handle() method should exit non-zero on failure (raise CommandError or return self.stderr.write with exit_code=1), and you ping a heartbeat monitor only when handle() returns cleanly.
How should a Django management command signal failure?
A management command that calls sys.exit(1) or raises a SystemExit causes manage.py to exit non-zero. Use CommandError for expected failure cases — Django converts it to stderr output and a non-zero exit:
from django.core.management.base import BaseCommand, CommandError
import urllib.request
PING_URL = "https://ping.cronshield.com/<your-check-id>"
class Command(BaseCommand):
help = "Send nightly reports"
def handle(self, *args, **options):
try:
send_all_reports()
except Exception as exc:
raise CommandError(f"report generation failed: {exc}") from exc
# Only reached if handle() returns cleanly — no exception.
urllib.request.urlopen(PING_URL, timeout=10)
self.stdout.write(self.style.SUCCESS("Reports sent"))With this pattern, a CommandError skips the ping and (if called from cron) produces output that triggers MAILTO. The heartbeat covers the silent-miss case where the cron entry was removed or the server was down.
How do I schedule and monitor it with cron?
# Run the command daily at 03:00. The && ensures the ping fires only on exit 0.
0 3 * * * /path/to/venv/bin/python /path/to/manage.py send_reports && curl -fsS -m 10 "https://ping.cronshield.com/<your-check-id>"What if I'm using Celery beat instead of cron?
If the management command is triggered by a Celery task (using call_command inside a Celery task), monitor the Celery beat scheduler as well. A dead beat process means the task is never dispatched, so the management command never runs — and the heartbeat monitor catches the silence.
Add a missed-run alert to this job
The free tier gives you a heartbeat endpoint and an email alert when an expected ping doesn't arrive. Paid tiers add the log-aware diagnosis — the last log line and a likely cause in the alert. The heartbeat receiver ships in an upcoming release; see the plans to learn what each tier adds.
Frequently asked questions
- Does Django log management command failures automatically?
- Django writes a CommandError to stderr and exits non-zero, but it does not push that to any external alerting system. If you run the command from cron with MAILTO set, the stderr output will be emailed. Without MAILTO or a heartbeat, the failure is silent.
- How do I test that the heartbeat fires correctly from manage.py?
- Run the command manually and confirm the ping reaches your monitor. Then introduce a deliberate CommandError and confirm no ping fires and the monitor would have alerted if the grace period passed.