How to monitor a Kubernetes CronJob
A Kubernetes CronJob can silently miss runs when the controller can't schedule it in time, when startingDeadlineSeconds is exceeded, or when concurrencyPolicy skips an overlapping run. To monitor it, have the job's container send a heartbeat to an external monitor on success and alert when the ping doesn't arrive in the expected window. Check missedStartsBeyondDeadline and the CronJob's lastScheduleTime when a run goes missing.
Why did my Kubernetes CronJob not run?
- startingDeadlineSeconds passed: if the controller can't start the job within that many seconds of its scheduled time (for example the control plane was busy), the run is counted as missed and skipped.
- concurrencyPolicy: Forbid: a previous run still in progress causes the new scheduled run to be skipped rather than queued.
- More than 100 missed schedules: if a CronJob is suspended or the controller is down and more than 100 start times are missed, the controller stops scheduling it and logs an error, requiring intervention.
- The job ran but the pod failed: image pull errors, an OOMKill, or a non-zero exit — the schedule fired but no useful work completed.
How do I send a heartbeat from a CronJob pod?
Add a heartbeat as the last thing the container does on success. If the job never schedules, never starts, or exits non-zero before the ping, no ping arrives and the monitor alerts:
apiVersion: batch/v1
kind: CronJob
metadata:
name: nightly-report
spec:
schedule: "0 3 * * *"
concurrencyPolicy: Forbid
startingDeadlineSeconds: 300
jobTemplate:
spec:
backoffLimit: 2
template:
spec:
restartPolicy: Never
containers:
- name: report
image: registry.example.com/nightly-report:latest
command: ["/bin/sh", "-c"]
# Ping only if the job command succeeds (&&, not ;).
args:
- "/app/run.sh && curl -fsS -m 10 --retry 3 https://ping.cronshield.com/<your-check-id>"How do I confirm whether the CronJob was scheduled?
When a run goes missing, inspect the CronJob to see when it last scheduled and whether it hit the deadline:
kubectl get cronjob nightly-report -o wide
kubectl describe cronjob nightly-report # look for "missed starts" / lastScheduleTimeA missed-ping alert tells you the run didn't complete; kubectl tells you whether it was a scheduling miss or a pod failure. On paid tiers, CronShield ingests the pod's stdout/stderr so a failed run's last log line and a likely cause land in the alert directly.
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 does my CronJob skip runs under load?
- If the controller can't start the job within startingDeadlineSeconds of the scheduled time, it records a missed start and skips that run. Raising the deadline gives more slack; a heartbeat monitor tells you when a skip actually happened.
- Does Kubernetes alert me when a CronJob fails?
- Not by default. The Job records failed pods, but nothing emails you. You need either Prometheus alerting on the kube_job_status_failed metric or an external heartbeat that alerts on a missing success ping.