Heroku Scheduler: Best-Effort Jobs, Clock Processes, and Monitoring
Heroku Scheduler runs a command every 10 minutes, hourly, or daily in UTC, with no guarantee it runs at all. What it does, why jobs go missing, clock processes, and check-ins.
Blog · Page 4 of 6
Why scheduled jobs miss runs or fail silently, and how to catch it in the schedulers you already use.
Heroku Scheduler runs a command every 10 minutes, hourly, or daily in UTC, with no guarantee it runs at all. What it does, why jobs go missing, clock processes, and check-ins.
Cron began in 1975 as a Bell Labs daemon reading one table every minute. How System V, BSD, Paul Vixie, POSIX, Linux, systemd, and Kubernetes shaped the cron you run today.
Schedulers retry, overlap, and catch up, so some runs happen twice. Working SQL and Python that turn the second run into a no-op: period claims, watermarks, upserts, idempotency keys, and an outbox.
Build periodically, triggers { cron() }, and properties() put Jenkins jobs on a schedule. How H hashing and TZ= work, why a scheduled build never ran, and a Jenkinsfile that checks in.
Why Laravel scheduled tasks stop running in production, from a missing schedule:run entry to a stale withoutOverlapping lock, with a way to confirm each cause and the fix for it.
Apple deprecated cron in favor of launchd. Write a LaunchAgent plist, load and inspect it with launchctl, see what sleep does to a schedule, and fix the jobs that silently never run.
CronRadar runs a hosted MCP server with 16 tools for scheduled-job monitoring. Configure the bearer header without committing the token, then ask your agent which jobs failed and why.
Cron skips it, anacron and persistent timers run it once, Kubernetes creates one Job, and strict misfire modes replay every run. Catch-up after downtime, checked against source code.
A backup that exits 0 can still be empty, missing off-site, or impossible to restore. A pg_dump script that checks its own output, a weekly restore drill, and alerts on the numbers.
Last-success timestamps through node_exporter or the Pushgateway, age and absent() rules, why a fixed age cannot follow a weekday schedule, a Watchdog for the stack, and the trade-offs.
An LLM job can exit 0 after a refusal, a max_tokens cutoff, or a quiet model change. Count what each run produced, score a small eval, and alert on those numbers, not only the exit code.
Render has a Cron Job service, Railway a Cron Schedule on any service, Fly.io fuzzy scheduled Machines, Supercronic, or Cron Manager. What each does when a run overlaps, fails, or never starts.
pg_cron records every run in cron.job_run_details and alerts on nothing. How the scheduler works, why jobs stop, and an outside reporter that turns each run into a check-in.
Cron starts a new run whether or not the last one finished. Choose a policy, use flock correctly, see why PID files fail and what Forbid really does, and lock across hosts.
A batch job that isn't running has nothing to scrape. How pull, push, and the hybrids between them detect missed, failed, and stuck runs, where each one goes blind, and which to use.
Why a Python script works in your terminal but not in cron, and how to fix it: the venv interpreter, uv, -m and sys.path, environment, unbuffered logs, exit codes, SIGTERM, and check-ins.
With RAMJobStore, every Quartz.NET instance runs every job. How a clustered AdoJobStore gives each firing to one node, recovers a dead node, and the misconfigurations that break it.
Start() never called, a paused group, a trigger with no next fire time, ERROR or BLOCKED states, a cron field off by one. How to confirm each cause from Quartz.NET itself, and the fix.
SmartPolicy, FireOnceNow, DoNothing, and IgnoreMisfirePolicy traced through the Quartz.NET 3.x source: the real misfireThreshold default, when misfires are detected, and a downtime timeline.
Solid Queue's recurring.yml, whenever's crontab, and GoodJob cron compared: schedule syntax, time zones, several servers, missed runs, why a job doesn't run, and check-ins that alert.