Set Concurrency Policy on CronJobs
Choose Forbid, Replace, or Allow intentionally, set deadlines and history limits, and make the job idempotent so an overlap cannot double-process data.
Task
Configure CronJob concurrency so scheduled runs do not silently overlap or pile up.
When to use this
A CronJob occasionally runs longer than its interval, and the default concurrency policy lets a second run start, double-processing the same window.
Prerequisites
- A Kubernetes cluster
- A container image for the job
Steps
1. Decide the concurrency policy based on whether overlap is safe.
Expected output: The behavior matches the job semantics.
2. Set activeDeadlineSeconds so a stuck run is killed.
Expected output: A hung job cannot run forever.
3. Set successful and failed history limits to bound stored Jobs.
Expected output: The namespace does not fill with old Jobs.
4. Make the job idempotent for the Allow case.
kubectl get cronjob nightly -o jsonpath='{.spec.concurrencyPolicy} {.spec.suspend}'Expected output: Overlap cannot double-apply changes.
Troubleshooting
Problem
Run skipped silently
Solution
With Forbid, a slow run skips the next tick; monitor missed runs and alert on skips.
Problem
Jobs accumulate
Solution
Set history limits and a deadline; unbounded completed Jobs consume quota.
Limitations
- CronJob scheduling is best-effort and can miss ticks under load or when suspended.
- Concurrency policies only govern overlaps of the same CronJob, not duplicates from multiple clusters.
Context
Configure CronJob concurrency so scheduled runs do not silently overlap or pile up. A CronJob occasionally runs longer than its interval, and the default concurrency policy lets a second run start, double-processing the same window.
Steps
- Decide the concurrency policy based on whether overlap is safe. Expected: The behavior matches the job semantics.
- Set activeDeadlineSeconds so a stuck run is killed. Expected: A hung job cannot run forever.
- Set successful and failed history limits to bound stored Jobs. Expected: The namespace does not fill with old Jobs.
- Make the job idempotent for the Allow case. Expected: Overlap cannot double-apply changes.
apiVersion: batch/v1
kind: CronJob
spec:
schedule: "0 2 * * *"
concurrencyPolicy: Forbid
startingDeadlineSeconds: 300
jobTemplate:
spec:
activeDeadlineSeconds: 1800
template:
spec: { restartPolicy: OnFailure, containers: [{ name: job, image: app:1.0 }] }
Verify
- The behavior matches the job semantics.
- A hung job cannot run forever.
- The namespace does not fill with old Jobs.
- Overlap cannot double-apply changes.
Limits
- CronJob scheduling is best-effort and can miss ticks under load or when suspended.
- Concurrency policies only govern overlaps of the same CronJob, not duplicates from multiple clusters.