How to monitor a systemd timer
A systemd timer stops firing when the timer unit is disabled, the machine was off past a non-persistent OnCalendar window, or the paired service unit fails. To monitor it, add an ExecStartPost (or a final ExecStart command) that pings an external monitor on success and alert when the ping doesn't arrive. Use systemctl list-timers to confirm the next and last trigger times.
Why did my systemd timer stop firing?
- The timer isn't enabled: a timer that was started but not enabled does not survive a reboot. Enable and start it with systemctl enable --now myjob.timer.
- A missed window without Persistent=true: if the machine was off or asleep during the OnCalendar window, the run is skipped unless Persistent=true is set, which catches up a missed run on next boot.
- The service unit failed: the timer fired on schedule but the paired .service exited non-zero, so the work didn't complete.
- A typo in OnCalendar: an unparseable calendar expression means the timer never has a valid next trigger. Validate it with systemd-analyze calendar.
How do I send a heartbeat from a systemd service?
Add an ExecStartPost that pings the monitor. systemd runs ExecStartPost only if the main ExecStart succeeded, so a failing job withholds the ping and triggers the alert:
[Unit]
Description=Nightly report job
[Service]
Type=oneshot
ExecStart=/usr/local/bin/nightly-report.sh
# Runs only if ExecStart succeeded. A failed job sends no ping.
ExecStartPost=/usr/bin/curl -fsS -m 10 --retry 3 https://ping.cronshield.com/<your-check-id>[Unit]
Description=Run the nightly report at 03:00
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
[Install]
WantedBy=timers.targetHow do I confirm the timer is active?
systemctl list-timers --all | grep nightly # NEXT / LAST trigger times
systemctl status nightly.timer nightly.service
journalctl -u nightly.service --since "1 day ago" # the job's own logslist-timers shows whether the timer has a valid next trigger; journalctl shows why the service failed. A missed-ping alert surfaces the outage; on paid tiers, CronShield pulls the service's output so the last log line and a likely cause arrive in the alert instead of you SSHing in to read journalctl.
Add a missed-run alert to this job
The free tier gives you a heartbeat endpoint and an email alert when an expected ping doesn't arrive. Paid tiers add the log-aware diagnosis — the last log line and a likely cause in the alert. The heartbeat receiver ships in an upcoming release; see the plans to learn what each tier adds.
Frequently asked questions
- Why didn't my systemd timer run while the server was rebooting?
- By default a timer skips any window that elapses while the machine is off. Set Persistent=true in the [Timer] section so systemd runs the job on next boot when a scheduled window was missed.
- How do I test a systemd timer without waiting for OnCalendar?
- Start the service directly with systemctl start nightly.service to run the job now, confirm the heartbeat ping arrives, then rely on the timer for the schedule.