Monitor systemd timers — success, failure, and silence
ExecStartPost pings on success. An OnFailure
unit pings on failure. And when the timer stops firing entirely —
masked unit, lost enablement, machine down — LastPing alerts on the
silence. Three small unit files, copy-paste below. Free, no monitor cap.
systemd remembers failures. It doesn't report them.
A failed unit sits patiently in systemctl --failed,
waiting for a human who isn't coming.
Failed units nobody lists
The unit fails, the state is recorded, the journal has the
traceback — and unless someone runs
systemctl --failed on that exact host, nobody ever
learns about it.
The timer that stops firing
A unit left disabled after a rebuild, a missing
Persistent=true so a powered-off window is skipped
forever, a rename that broke WantedBy — the timer
doesn't fail. It just stops existing.
The journal as a write-only medium
Errors land in the journal with perfect fidelity and zero reach. Journald is superb at recording what happened — and mute about telling you.
Setup: three unit files
The example monitors a nightly backup; rename to match your job. If
curl lives elsewhere on your distro, check with
which curl.
Create a heartbeat monitor
In the console, create a monitor matching the timer's schedule (a simple interval or a cron expression with an IANA timezone) plus a grace window, and copy the ping URL.
The service — ping on success
For Type=oneshot, ExecStartPost runs
only after ExecStart exits successfully — so the
ping means the job actually worked:
The failure reporter — alert immediately
OnFailure starts this unit whenever the service
enters a failed state. It's optional — a failed run also sends
no success ping, so the grace window would alert anyway — but
/fail makes it immediate:
The timer
Persistent=true runs a missed activation at the
next boot instead of skipping it silently:
Enable and test the whole loop once
Optional: catch hung runs too
An ExecStartPre ping to /start arms
overrun detection — if the matching success doesn't arrive
inside the grace window, LastPing opens an incident while the
job is still wedged:
What this catches
The units report what they can; the silence reports the rest.
- The service failed —
OnFailurepings/failand you're alerted immediately, journal intact for the post-mortem. - The timer stopped firing — disabled unit, broken enablement, masked service. No ping in the expected window → incident.
- The machine is down — nothing on the host can report that; the absence of the ping does.
- The job hung — with the
/startping armed, a run that never completes inside grace opens an incident. - Recovery — the next successful run closes the incident and sends a recovery notice automatically.
Still on classic cron for some hosts? The cron guide is the same pattern in one crontab line. Backup jobs deserve the fuller start → work → success/fail pattern — or browse all guides.
Questions people ask
Front-loaded answers — the most important fact first.
-
Does ExecStartPost run if the service fails?
No — for
Type=oneshotservices,ExecStartPostcommands run only afterExecStarthas exited successfully. That's exactly the behavior you want: a failed job sends no success ping, and the missed ping (or theOnFailureunit pinging/fail) raises the alert. -
How do I get an immediate alert when the service fails?
Add
OnFailure=backup-fail.serviceto the[Unit]section, where the referenced unit is a oneshot that curls the/failendpoint. The explicit failure signal opens an incident immediately instead of waiting out the grace window. -
What if the whole machine is off?
The timer can't fire and nothing on the host can self-report — but LastPing alerts anyway, because the expected ping never arrives. Absence-based detection covers every failure mode, including the ones the machine can't see.
-
systemd timer or cron — does it matter for monitoring?
No. Both patterns end in the same ping to the same URL; systemd just gives you nicer hooks (
ExecStartPost,OnFailure) than a shell&&. The cron guide covers the crontab one-liner. -
Is this free?
Yes. LastPing is free and fully hosted with no monitor cap and no paid tier. See how it compares to Healthchecks.io and Cronitor.
systemctl --failed is a list of alerts you never got.
Three unit files now beat a journal archaeology session later. First alert wired up in minutes — and LastPing monitors itself the same way.