The failure this catches
Heroku calls Scheduler best effort. It gives no guarantee that a command runs at the scheduled time, or at all. Rarely, it can skip a job or run it twice. Neither outcome gives PostDeploy a completed run to poll.
A heartbeat gives the missing signal. Your command reports only after its useful work succeeds. If a run is skipped or delayed past its grace period, PostDeploy opens an incident. Make the command safe to repeat because a heartbeat detects duplicate scheduling after the fact.
Add the ping to the command
Create a heartbeat monitor with the same cadence as the Scheduler entry. Give it a grace period that covers normal queue delay. In the Heroku dashboard, append the curl command with && so it runs only after the task exits successfully.
./bin/nightly-report && curl -fsS https://ingest.postdeploy.dev/h/hb_YOUR_TOKEN
Report a failure immediately
Use the exit code form when the task can fail before the next expected heartbeat. It keeps the task exit code unchanged and tells PostDeploy whether the run failed.
./bin/nightly-report; code=$?; curl -fsS https://ingest.postdeploy.dev/h/hb_YOUR_TOKEN/$code; exit $code
Test the monitor
Run the command once from a one-off dyno or your local shell with the real token. Confirm the monitor records a passing heartbeat. Then force a non-zero exit once and confirm that PostDeploy creates an incident.
heroku run './bin/nightly-report && curl -fsS https://ingest.postdeploy.dev/h/hb_YOUR_TOKEN' --app your-app
Questions
Why did my Heroku Scheduler job not run?
Heroku Scheduler is best effort. Its documentation says a job has no guarantee of running at its scheduled time, or at all. A heartbeat alerts when the expected successful run never reports.
Can Heroku Scheduler run my job twice?
Yes, rarely. Make the task idempotent. A heartbeat reports that a run completed, but it does not make duplicate work safe.
What PostDeploy does not do here
- PostDeploy does not inspect Heroku Scheduler run history
- PostDeploy does not prevent a scheduled job from running twice
- PostDeploy does not restart a skipped dyno command
Sources
Links are the platform's own documentation for the failure mode described above.
- Heroku Scheduler Checked