Owl Keeper

Features / Scheduled jobs

Cron job monitoring

A cron job that stops running does not fail loudly — it fails silently, and you find out on the day you need what it was producing. Cron job monitoring turns that silence into an alert by having the job report in, and telling you when a report does not arrive.

The failure this catches

A cron entry is lost in a server migration. The nightly database dump stops running. Nothing breaks, nothing alerts, and the site carries on answering 200 for four months — until the morning somebody needs to restore, which is the most expensive possible day to discover that the backup directory stopped growing in April.

Every other check here works by asking a question and reading the answer: is the site up, has the certificate expired, does the DMARC record still parse. None of them can see this one. A server whose backup script was deleted is a completely healthy server, and it will pass every uptime check you can point at it for as long as you care to keep pointing.

How it works

The check runs the other way round. Instead of something reaching out to your job, your job reaches out when it finishes:

0 3 * * * /usr/local/bin/backup.sh && curl -fsS https://owlkeeper.com/ping/YOUR-TOKEN

That is the whole integration. There is no agent to install, no library to add to a project, and nothing to keep updated when the language runtime moves on.

Two details in that line are worth being deliberate about:

  • && rather than ;. With && the ping only happens if the script exited zero. A backup that fails halfway and exits 1 never reports in, so you are told. With ; the ping fires regardless and you have built a monitor that confirms cron is running rather than that the backup worked.
  • -fsS. Fail quietly on an HTTP error, stay silent on success, but still print real errors. Without it, curl writes a progress meter into cron's output and you get a mail from root every night.

What counts as late

You set an expected interval and a grace period. A job due hourly with five minutes of grace is not late at 1:01; it is late at 1:05. That distinction is the difference between a monitor you keep and one you mute in week three, because a nightly job that usually finishes at 03:04 and occasionally at 03:11 is not a job with a problem.

Nothing is reported until a run has actually been missed. Setting a monitor up in the afternoon for a job that runs at three in the morning does not alert you that evening — a job that has never reported in is not overdue, it is new.

What the alert says

Not "the job is down", which is a question. The alert names the job and says when it last reported, which is an answer:

Nightly backup has not reported in. Last run was 9 hours ago.

That sentence is usually enough to know whether you are looking at a crashed script, a full disk, or a server that was rebuilt last night without its crontab.

You are told once. A job that has stopped stays stopped until somebody fixes it, and an alert that repeats every hour until then is an alert people build a mail filter for. When the job reports in again, you get a recovery notice and the incident closes itself.

Runs behind a firewall

Because nothing is requested from this side, there is no inbound connection to allow. A job on a build box, a laptop, a client's server behind a corporate NAT, or a container that only exists for ninety seconds reports in exactly the same way as one on a public host. This is the only check here that works on machines with no public address at all.

How long the run took

A job can report its own duration by adding it to the ping:

START=$(date +%s%3N)
/usr/local/bin/import.sh
curl -fsS "https://owlkeeper.com/ping/YOUR-TOKEN?ms=$(( $(date +%s%3N) - START ))"

That gives the job a duration history alongside the pass or fail. It is the signal that catches the slow problem rather than the sudden one: an import that took four minutes in January and takes thirty-one now is a job that will start failing, and the graph says so weeks before the timeout does.

The parameter is optional. A ping without it is a perfectly good ping.

What it costs

Nothing extra. Scheduled jobs are checked on every plan, including the free one, and a cron monitor does not consume a site — the ten free sites are ten sites, however many jobs each of them reports.

Questions

Does this replace Cron itself?

No. Your scheduler stays exactly as it is. This watches whether what it was supposed to run actually ran, which is a different question from whether the scheduler is alive.

What if the job runs but produces nothing useful?

Then it will ping, and you will not be told. A heartbeat proves a script reached its last line, not that it did anything worth doing. For a backup, the honest pairing is a ping at the end of the script plus a check inside it that the file it just wrote is a plausible size — and to fail the script if it is not, so the && never fires.

Can two jobs share one URL?

They can, and it is almost always a mistake. Each token is one job's identity; pointing two at the same one means either can satisfy the other's window, and the alert cannot tell you which one stopped.

Is the ping URL secret?

The token is the entire credential, so treat it like one. Anybody who has it can report that your job ran. It appears in your crontab and in nothing else — it is never shown on a status page, and the endpoint is rate limited well above any sane cron frequency.

GET or POST?

Either. curl defaults to GET and a job posting its duration may prefer POST; both are accepted, because refusing one would be a footgun in a file nobody looks at again for two years.