Kubernetes CronJob ConcurrencyPolicy Guide
Configure Kubernetes CronJob concurrencyPolicy with Allow, Forbid, and Replace options. Control concurrent job execution, prevent overlapping runs, and handle
π‘ Quick Answer:
concurrencyPolicycontrols what happens when a CronJobβs next schedule fires while a previous run is still active.Allow(default) runs jobs concurrently.Forbidskips the new run if previous is still running.Replacecancels the running job and starts a new one. UseForbidfor most production workloads to prevent resource contention.
The Problem
- CronJob fires every 5 minutes but the job takes 7 minutes β overlapping runs compete for resources
- Concurrent database backup jobs corrupt data
- Multiple parallel report generators consume all available memory
- Need to guarantee only one instance of a periodic job runs at a time
- Long-running jobs should be replaced by fresh runs (not accumulate)
The Solution
ConcurrencyPolicy Options
ββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Allow β Default. Multiple jobs can run simultaneously. β
β β Good for: stateless, independent tasks (send emails) β
β β Risk: resource contention, duplicate processing β
ββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Forbid β Skip new run if previous is still active. β
β β Good for: database backups, exclusive locks, ETL pipelines β
β β Behavior: "missed" schedule is simply skipped β
ββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Replaceβ Cancel running job, start new one. β
β β Good for: cache refresh, status sync, "latest wins" β
β β Behavior: old job terminated, new job starts fresh β
ββββββββββ΄βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββAllow (Default)
apiVersion: batch/v1
kind: CronJob
metadata:
name: send-notifications
spec:
schedule: "*/5 * * * *"
concurrencyPolicy: Allow # Multiple can run in parallel
jobTemplate:
spec:
template:
spec:
containers:
- name: notify
image: registry.example.com/notify:v1
restartPolicy: NeverForbid (Exclusive Execution)
apiVersion: batch/v1
kind: CronJob
metadata:
name: database-backup
spec:
schedule: "0 2 * * *" # Daily at 2 AM
concurrencyPolicy: Forbid # Never run 2 backups simultaneously
startingDeadlineSeconds: 3600 # Allow 1h late start
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 3
jobTemplate:
spec:
activeDeadlineSeconds: 7200 # Kill if running > 2 hours
template:
spec:
containers:
- name: backup
image: registry.example.com/db-backup:v1
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-credentials
key: url
restartPolicy: NeverReplace (Latest Wins)
apiVersion: batch/v1
kind: CronJob
metadata:
name: cache-refresh
spec:
schedule: "*/10 * * * *"
concurrencyPolicy: Replace # Kill old, start fresh
jobTemplate:
spec:
template:
spec:
containers:
- name: refresh
image: registry.example.com/cache-refresh:v1
restartPolicy: NeverCheck CronJob Status
# List CronJobs and last schedule
kubectl get cronjobs
# NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
# database-backup 0 2 * * * False 0 8h 30d
# cache-refresh */10 * * * * False 1 2m 7d
# Check active (running) jobs
kubectl get jobs --selector=job-name -l cronjob=database-backup
# See if jobs were skipped (Forbid policy)
kubectl describe cronjob database-backup
# Events:
# Normal SawCompletedJob 5m cronjob-controller Saw completed job: database-backup-xxx
# Normal SkippedConcurrent 2m cronjob-controller Skipped concurrent run (Forbid)Common Issues
Jobs accumulating with Allow policy β resource exhaustion
- Cause: Jobs take longer than schedule interval; unlimited concurrency
- Fix: Switch to
ForbidorReplace; setactiveDeadlineSecondson jobs
CronJob βmissed starting windowβ β job never runs
- Cause:
startingDeadlineSecondstoo short; scheduler was down during window - Fix: Set
startingDeadlineSeconds: 200(or higher); check scheduler health
Replace terminates job mid-work β data corruption
- Cause:
Replacekills running job without graceful shutdown - Fix: Use
Forbidinstead for data-sensitive jobs; or implement graceful shutdown handling
Best Practices
- Default to
Forbidβ safest for most production workloads - Set
activeDeadlineSecondsβ prevent runaway jobs from blocking forever - Set
startingDeadlineSecondsβ allow late starts after brief scheduler unavailability - Use
Replaceonly for idempotent tasks β where βlatest data winsβ is acceptable - Set history limits β
successfulJobsHistoryLimit: 3prevents old job accumulation - Monitor skipped runs β alert if
Forbidis consistently skipping schedules
Key Takeaways
concurrencyPolicycontrols behavior when CronJob schedule fires during active runAllow: concurrent runs OK (default, risky for stateful jobs)Forbid: skip if still running (safest for exclusive workloads)Replace: kill running job, start fresh (for βlatest winsβ scenarios)- Always pair with
activeDeadlineSecondsto prevent infinite-running jobs - Check for skipped runs in CronJob events when using
Forbid

Recommended
Kubernetes Recipes β The Complete Book100+ production-ready patterns with detailed explanations, best practices, and copy-paste YAML. Everything in one place.
Get the Book βLearn by Doing
CopyPasteLearn β Hands-on Cloud & DevOps CoursesMaster Kubernetes, Ansible, Terraform, and MLOps with interactive, copy-paste-run lessons. Start free.
Browse Courses βπ Deepen Your Skills β Hands-on Courses
Courses by CopyPasteLearn.com β Learn IT by Doing
