πŸ“šBook Signing at KubeCon EU 2026Meet us at Booking.com HQ (Mon 18:30-21:00) & vCluster booth #521 (Tue 24 Mar, 12:30-1:30pm) β€” free book giveaway!RSVP Booking.com Event
Configuration beginner ⏱ 10 minutes K8s 1.28+

Kubernetes CronJob concurrencyPolicy Explained

Configure Kubernetes CronJob concurrencyPolicy: Allow, Forbid, and Replace. Control overlapping job execution, prevent duplicate runs, and handle slow jobs.

By Luca Berton β€’ β€’ πŸ“– 5 min read

πŸ’‘ Quick Answer: `concurrencyPolicy` controls what happens when a CronJob triggers while a previous run is still active. `Allow` (default) lets jobs overlap. `Forbid` skips the new run. `Replace` terminates the old run and starts a new one.

The Problem

CronJobs that take longer than their schedule interval create overlapping runs. A backup job scheduled every 5 minutes that takes 7 minutes will pile up concurrent instances, competing for resources and potentially corrupting data. The `concurrencyPolicy` field controls this behavior.

flowchart TB
    subgraph ALLOW["concurrencyPolicy: Allow"]
        A1["Job 1 (running)"]
        A2["Job 2 (starts anyway)"]
        A3["Job 3 (starts anyway)"]
    end
    subgraph FORBID["concurrencyPolicy: Forbid"]
        F1["Job 1 (running)"]
        F2["Job 2 (SKIPPED)"]
        F3["Job 3 (runs after Job 1)"]
    end
    subgraph REPLACE["concurrencyPolicy: Replace"]
        R1["Job 1 (terminated)"]
        R2["Job 2 (replaces Job 1)"]
    end

The Solution

Allow (Default)

Multiple jobs can run simultaneously:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: data-sync
spec:
  schedule: "*/5 * * * *"         # Every 5 minutes
  concurrencyPolicy: Allow        # Default β€” jobs can overlap
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: sync
              image: busybox
              command: ["sh", "-c", "echo syncing; sleep 600"]
          restartPolicy: Never

Use when: Each job run is independent and idempotent (e.g., sending notifications, collecting metrics).

Forbid

Skip the new run if the previous one is still active:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: database-backup
spec:
  schedule: "0 * * * *"           # Every hour
  concurrencyPolicy: Forbid       # Skip if previous still running
  startingDeadlineSeconds: 300    # Allow 5-min late start
  jobTemplate:
    spec:
      activeDeadlineSeconds: 3600  # Kill if running > 1 hour
      template:
        spec:
          containers:
            - name: backup
              image: postgres:16
              command: ["pg_dump", "-h", "db", "-U", "admin", "mydb"]
          restartPolicy: Never

Use when: Only one instance should ever run (backups, migrations, cleanup jobs).

Replace

Terminate the running job and start a new one:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: cache-refresh
spec:
  schedule: "*/10 * * * *"        # Every 10 minutes
  concurrencyPolicy: Replace      # Kill old, start new
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: refresh
              image: redis:7
              command: ["redis-cli", "BGSAVE"]
          restartPolicy: Never

Use when: Only the latest run matters and old runs are stale (cache refresh, report generation).

Comparison Table

PolicyOverlap?Old JobNew JobUse Case
Allowβœ… YesKeeps runningStartsIndependent, idempotent tasks
Forbid❌ NoKeeps runningSkippedMutual exclusion (backups, locks)
Replace❌ NoTerminatedStartsLatest-wins (cache refresh)
spec:
  schedule: "*/5 * * * *"
  concurrencyPolicy: Forbid

  # How many seconds late a job can start (from scheduled time)
  startingDeadlineSeconds: 200

  # Keep N successful/failed job history
  successfulJobsHistoryLimit: 3
  failedJobsHistoryLimit: 1

  # Suspend scheduling (pause without deleting)
  suspend: false

  jobTemplate:
    spec:
      # Kill job if running longer than this
      activeDeadlineSeconds: 3600

      # Retry failed pods up to N times
      backoffLimit: 3

      # Time-to-live cleanup after completion
      ttlSecondsAfterFinished: 300

Monitor CronJob Behavior

# Check CronJob status
kubectl get cronjobs
# NAME              SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE
# database-backup   0 * * * *     False     1        35m

# Check active jobs
kubectl get jobs --selector=job-name=database-backup

# Check if jobs were skipped (Forbid policy)
kubectl describe cronjob database-backup
# Events:
#   Warning  MissSchedule  Missed scheduled time ... because concurrencyPolicy is Forbid

# Watch job execution
kubectl get jobs -w

Common Issues

IssueCauseFix
Jobs piling up`Allow` policy with slow jobsSwitch to `Forbid` or `Replace`
Jobs never startPrevious job stuck, policy is `Forbid`Add `activeDeadlineSeconds` to kill stuck jobs
Data corruptionConcurrent jobs writing same resourceUse `Forbid` policy
Missing runs with `Forbid`Jobs consistently exceed scheduleIncrease interval or optimize job
CronJob stopped scheduling>100 missed startsSet `startingDeadlineSeconds`

Best Practices

  • Use `Forbid` for stateful operations β€” backups, migrations, writes to shared resources
  • Use `Replace` for cache/report jobs β€” latest run is the only one that matters
  • Set `activeDeadlineSeconds` β€” prevents stuck jobs from blocking `Forbid` forever
  • Set `startingDeadlineSeconds` β€” avoids CronJob controller giving up after 100 missed starts
  • Clean up history β€” `successfulJobsHistoryLimit: 3` prevents orphaned job objects
  • Monitor with `kubectl describe cronjob` β€” check for MissSchedule events

Key Takeaways

  • `concurrencyPolicy` controls overlapping CronJob runs: Allow, Forbid, or Replace
  • `Forbid` skips new runs while old is active β€” safest for stateful operations
  • `Replace` kills old run and starts new β€” ideal for latest-wins scenarios
  • Always pair `Forbid` with `activeDeadlineSeconds` to prevent permanent blocking
  • Default is `Allow` β€” explicitly set the policy for production CronJobs
#cronjob #concurrency #scheduling #batch-jobs #job-management
Luca Berton
Written by Luca Berton

Principal Solutions Architect specializing in Kubernetes, AI/GPU infrastructure, and cloud-native platforms. Author of Kubernetes Recipes and creator of CopyPasteLearn courses.

Kubernetes Recipes book cover

Want More Kubernetes Recipes?

This recipe is from Kubernetes Recipes, our 750-page practical guide with hundreds of production-ready patterns.

Luca Berton Ansible Pilot Ansible by Example Open Empower K8s Recipes Terraform Pilot CopyPasteLearn ProteinLens