← Knowledge hub
Guideby Uptime Room· September 24, 2026· 6 min read

Heartbeat Monitoring: Catch Jobs That Never Ran

Heartbeat monitoring waits for your cron job to check in, then alerts when the signal never arrives. Here is how to size the grace period.

Heartbeat monitoring inverts the usual check. Instead of a probe calling your service, your job calls the monitor. A nightly backup, an invoice run or a queue worker sends a request to a unique URL when it finishes. If that request never arrives inside the expected window, an alert fires and somebody finds out the job died.

What is a heartbeat check?

Heartbeat monitoring is an inbound check that waits for a signal your own code sends. The monitor stores an expected period and a grace period. When the window closes with no signal, the state flips and an alert routes to whoever owns the job. Cronitor's guide calls this a time-tested way to track the health of a device or a software system.

The older name is a dead man's switch. Silence is the failure signal, not a status code. That is why the pattern catches a class of failure an outbound probe never sees: the job that never started at all.

How does a heartbeat check work?

Three values define the check: a unique URL, an expected period and a grace period. Your job sends an HTTP request to that URL on success. The monitor records the timestamp, then counts down from period plus grace.

A backup that runs hourly gets a 3,600-second period. Give it a 600-second grace window and the monitor stays quiet until 70 minutes of silence have passed. At that point it stops waiting and pages someone. Checkly's docs describe the same shape as a passive check that waits for automated tasks to report completion.

The signal has to come from the end of the job, after the work succeeded. A ping at the top of the script proves only that cron fired.

Setting up heartbeat monitoring

Create the monitor first, then wire the request into the last line of your job. Heartbeat is one of ten monitor types, alongside http, api, keyword, tcp, dns, ping, udp, ssl and domain:

curl -X POST https://uptimeroom.com/api/v1/monitors \
  -H "Authorization: Bearer urm_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "nightly invoice run",
    "type": "heartbeat",
    "intervalSec": 86400,
    "alertAfterCycles": 1
  }'

The response carries the ping URL. Call it from inside the job, never from a wrapper that runs whether or not the work succeeded:

#!/usr/bin/env bash
set -euo pipefail

python3 /srv/billing/run_invoices.py
curl -fsS --retry 3 https://uptimeroom.com/api/heartbeat/<token> > /dev/null

That set -euo pipefail line matters more than it looks. Without it a failing Python step still falls through to the curl call and reports a healthy run. The bash manual documents each flag, and the REST API reference covers the remaining monitor fields.

Choosing an interval and a grace period

The grace period absorbs normal variance in run time. Set it too tight and every slow night pages you. Set it too loose and a dead job stays invisible for hours. We tested a nightly job that usually finished in nine minutes and occasionally took nineteen. A 30-minute grace period was the first value that produced no false alerts across two weeks.

Job cadenceExpected periodGrace we would start with
Every 5 minutes300s120s
Hourly3,600s600s
Nightly86,400s1,800s
Weekly604,800s7,200s

Widen the window only after you have seen the real distribution of run times. Response-time history keeps p50, p95 and p99, so last month's p99 beats a guess every time.

One caveat on very frequent jobs. If a task runs every minute, a grace period shorter than the run time itself guarantees noise, because a single slow pass overlaps the next expected window. Either lengthen the grace period past the worst observed run, or accept that a one-minute job needs a different pattern entirely.

Heartbeat monitoring outside cron

The pattern is not limited to crontab. Anything that runs on a schedule and can make an outbound request fits, which covers more of a modern stack than people expect.

A Kubernetes CronJob works the same way, with the call placed in the container's entrypoint after the workload exits zero. A serverless function on a timer can report at the end of its handler, though you should put the call inside the success branch rather than in a finally block. A Windows scheduled task can use Invoke-WebRequest on its last line.

Long-running workers are the interesting case. A consumer that should never stop can report every five minutes from inside its main loop, which turns a silent hang into a page. That catches the deadlock a process-level restart policy will happily ignore, because the process is still alive and still doing nothing.

What this check cannot tell you

Heartbeat monitoring proves a job finished. It says nothing about whether the job did the right thing. An invoice run that processes zero rows and exits cleanly still reports on time, and the monitor stays green all week.

Two fixes are worth the effort. Send the signal only after asserting the work was non-trivial, such as a row count above zero. Or pair the check with a content assertion against a page that renders the result, which is what keyword monitoring is for.

Queue depth and memory pressure inside the process stay out of reach here. Those need something running in-process rather than an external probe, which is the saturation gap described in the four golden signals.

Common mistakes

Pinging from a wrapper. A cron line like run.sh; curl ... reports success even after a crash. Chain the two with &&, or use set -e and put the call last.

Forgetting the retry flag. One dropped packet should not page anyone. curl --retry 3 -fsS costs nothing and removes most network noise, the same reasoning behind cross-region quorum confirmation on outbound checks.

One signal for a fan-out job. If a job spawns twenty workers, a single call tells you the parent lived. Give each worker its own monitor, or report only after every child has been reaped.

Leaving the grace period at its default. Defaults are guesses. A weekly job with a five-minute grace window will page you on the first slow week.

Alert routing and history

Heartbeat monitoring is worth little if the alert lands somewhere nobody reads. Route job failures to the channel the owning team already watches rather than to a shared firehose. There are 16 alert channel types, including Slack, PagerDuty, Opsgenie, webhooks, SMS and voice calls.

History retention as of September 2026 runs one month on the free plan, one year on Individual and two years on Enterprise. A year of history is what lets you show that a job has been drifting slower for three months rather than failing out of nowhere.

Start with your least-observed job, the one that could go unnoticed for a full day. Give it a realistic grace period and an alert route with a name attached. The free plan covers 10 monitors at a 1-minute interval as of September 2026. That is enough to put heartbeat monitoring on every scheduled job that matters before you pay anything.

FAQ

What is heartbeat monitoring in software systems?

It is an inbound check. Your scheduled job sends a request to a unique URL when it finishes successfully, and the monitor raises an alert if that request does not arrive within the expected period plus a grace window. Silence is the failure signal, which is why the pattern catches jobs that never ran at all.

How is a heartbeat check different from an uptime check?

An uptime check is outbound: a probe calls your URL on a schedule and reports what came back. A heartbeat check is inbound and waits for your code to call it. Outbound checks cannot see a cron job at all, because a job that never fires leaves no endpoint for a probe to test.

How long should a heartbeat grace period be?

Start from the p99 run time of the job rather than the average. For a nightly job that usually takes nine minutes and sometimes nineteen, thirty minutes of grace produced no false alerts in our two-week test. Hourly jobs do well at ten minutes, and weekly jobs need a couple of hours.

Is there a free way to monitor cron jobs?

Yes. The Uptime Room free plan includes 10 monitors and a 1-minute check interval as of September 2026, and heartbeat is one of the ten available monitor types. That is usually enough to cover every scheduled job that would otherwise fail silently, including backups and billing runs.

Related reading