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.
Your assistant can do this for you
Monitor my systemd timers with LastPing
On this page
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.
https://ping.lastping.dev/<your-monitor-id>
The service: ping on success
For Type=oneshot, ExecStartPost runs
only after ExecStart exits successfully, so the
ping means the job actually worked:
# /etc/systemd/system/backup.service
[Unit]
Description=Nightly backup
OnFailure=backup-fail.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
ExecStartPost=/usr/bin/curl -fsS -m 10 --retry 3 -o /dev/null https://ping.lastping.dev/<your-monitor-id>
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:
# /etc/systemd/system/backup-fail.service
[Unit]
Description=Report backup failure to LastPing
[Service]
Type=oneshot
ExecStart=/usr/bin/curl -fsS -m 10 --retry 3 -o /dev/null https://ping.lastping.dev/<your-monitor-id>/fail
The timer
Persistent=true runs a missed activation at the
next boot instead of skipping it silently:
# /etc/systemd/system/backup.timer
[Unit]
Description=Run nightly backup at 03:00
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
[Install]
WantedBy=timers.target
Enable and test the whole loop once
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
# run the service once by hand — the ping should land in the console
sudo systemctl start backup.service
# confirm the next scheduled activation
systemctl list-timers backup.timer
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:
ExecStartPre=/usr/bin/curl -fsS -m 10 --retry 3 -o /dev/null https://ping.lastping.dev/<your-monitor-id>/start
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.
-
How do I monitor a systemd timer?
Add
ExecStartPost=/usr/bin/curl -fsS -m 10 --retry 3 -o /dev/null https://ping.lastping.dev/<your-monitor-id>to the service unit. ForType=oneshotservices,ExecStartPostruns only afterExecStartexits successfully, so the ping means the job actually worked. LastPing expects that ping on the timer’s schedule and alerts when it does not arrive. -
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 a systemd 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 down?
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 is the point: it 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 systemd timer monitoring free?
Yes. LastPing is free for individuals with no monitor cap. 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.