The job that never runs is the most dangerous — and the hardest to detect. This episode exports duration and status to Prometheus via the node_exporter textfile collector, detects missing jobs with on-miss alerting, and audits crontab changes with periodic reviews.

In episode 19 we managed distributed scheduling. Now we answer the nagging question: how do you know a job isn't running — before it's too late?
In episode 12 we built alerts for when a job fails (exit code != 0). But there's a sneakier failure: a job that never appears at all — a host is down, a crontab was deleted, a schedule was missed due to DST, or a cluster controller misbehaves. No exit code, no email, nothing. Detecting this kind of failure requires observability and auditing.
The simplest pattern for job metrics from a host: the node_exporter textfile collector. The job script writes metrics to a .prom file, and node_exporter reads it when scraped.
#!/bin/bash
set -uo pipefail
DIR=/var/lib/node_exporter/textfile
START=$(date +%s)
STATUS=0
if /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1; then
STATUS=1
else
STATUS=0
fi
END=$(date +%s)
printf '# HELP cron_backup_success 1 jika backup sukses\n' > "$DIR/backup.prom"
printf '# TYPE cron_backup_success gauge\n' >> "$DIR/backup.prom"
printf 'cron_backup_success 1\n' >> "$DIR/backup.prom" # status 1
printf '# TYPE cron_backup_duration_seconds gauge\n' >> "$DIR/backup.prom"
printf 'cron_backup_duration_seconds %d\n' "$((END - START))" >> "$DIR/backup.prom"The resulting metrics:
# TYPE cron_backup_success gauge
cron_backup_success 1
# TYPE cron_backup_duration_seconds gauge
cron_backup_duration_seconds 42Note
For hosts with several jobs, don't write a separate .prom file per job without a clean naming convention — node_exporter reads every .prom file in the directory. Name them after the job (backup.prom, cleanup.prom) and make sure the directory is writable by the user running the job.
The cron_backup_success metric only exists if the job finished writing it. If the job never runs, the metric isn't updated — and this is where on-miss alerts show their power:
groups:
- name: cronjob
rules:
- alert: CronJobMissed
expr: time() - cron_backup_success > 90000
annotations:
summary: Backup tidak muncul selama 25 jam - alert: CronJobMissing
expr: absent(cron_backup_success)
for: 24h
annotations:
summary: Metrik backup hilang — job mungkin tidak pernah jalanThe key difference: on-failure alerts (episode 12) catch jobs that failed; on-miss alerts catch jobs that never started. You need both.
kubectl get cronjobs -A -o wide
kubectl get jobs -AAlso set up a Blackbox/Probe for services that a job is supposed to update — e.g. a version file on an HTTP endpoint that a periodic backup refreshes; if its contents go stale, there's a problem.
From episode 5, /var/log/cron records every execution. Add auditing at the user level:
sudo auditctl -w /var/spool/cron/ -p wa -k cron-change
sudo ausearch -k cron-change --start todayThis answers "who changed the crontab and when" — important when schedules change without the team knowing.
Observability without process is idle data. Adopt a ritual:
crontab -l per user) — is every job still needed?crontab file + PR, from episode 4).for u in $(cut -d: -f1 /etc/passwd); do
sudo crontab -l -u "$u" 2>/dev/null && echo "--- $u ---"
doneTip
One observability metric + one on-miss alert per critical job, plus change auditing — that's a sufficient foundation for production jobs. Start with the most critical jobs (backup, restore, payment), not all jobs at once.
| Layer | Catches | Tool |
|---|---|---|
| On-failure alert | Job ran but failed | Exit code + webhook (ep. 12) |
| Textfile metrics | Duration, status | node_exporter + Prometheus |
| On-miss alert | Job never appeared | absent() / staleness |
| Audit log | Crontab changes | auditd + /var/log/cron |
| Periodic review | Stale/ownerless jobs | Monthly ritual |
Key takeaways:
In episode 21 we'll cover roadmap and community — where cronie is headed, the migration trends toward systemd timers and K8s CronJob, and the learning ecosystem: crontab.guru, man 5 crontab, and distro documentation!