Know when your cron jobs silently stop

Cron tells you nothing when the server is down, the crontab was overwritten or a job hangs. Paste your crontab: get next runs, the longest healthy silence, a sensible grace period, a wrapped line that reports success or failure, and the config for a heartbeat monitor you run yourself — one Node file, no dependencies, no account.

Your crontab

Run the monitor

curl -O https://raw.githubusercontent.com/Duncan-Haywood/fp-monorepo/main/ventures/cron-heartbeat/{server,monitor,cron}.mjs
CONFIG=checks.json PING_KEY=choose-a-secret \
ALERT_WEBHOOK_URL=https://hooks.slack.com/... node server.mjs

Put it behind HTTPS (Caddy or nginx) on a box that is not the one running the jobs. Alerts go only to the webhook or ALERT_NTFY_URL topic you set. State is a JSON file next to it. Pings accept GET or POST at /ping/<name>, /ping/<name>/start and /ping/<name>/fail; /status returns every check as JSON. Add ?key= to each URL when PING_KEY is set.

Questions

How do I know if a cron job stopped running?

Cron only reports errors it can mail, and silently does nothing when the machine is down, the crontab is overwritten or the job hangs. A heartbeat (dead man's switch) inverts this: the job pings a URL when it succeeds, and the monitor alerts when the ping does not arrive within the schedule plus a grace period.

What grace period should I use?

Long enough to cover normal run time and scheduler jitter, short enough that a missed run is noticed while it still matters. This tool suggests about 10% of the typical interval, between 1 minute and 1 hour; raise it for jobs that take a long time to finish.

Does it report failures as well as silence?

Yes. The wrapped command pings /ping/name when the job exits 0 and /ping/name/fail when it does not. A /start ping is also supported so a job that starts and never finishes is distinguished from one that never started.

What does the monitor store, and what does it cost?

It is one Node.js file with no dependencies that keeps check names and last-ping times in a JSON file on your own machine. Alerts go only to the webhook or ntfy topic you configure. There is no account and no cost; you pay only for the box it runs on.

Which timezone does it use?

UTC by default. Put a CRON_TZ=Europe/London line above a job in the pasted crontab, or set "tz" on a check, and the schedule is read in that zone, daylight saving included: a repeated hour counts once and a skipped hour is skipped that day. The host timezone is never used. See also the Cron DST Drift Check.