Try the Cron Explainer

Kubernetes CronJob vs Traditional Cron — ConcurrencyPolicy, TimeZone Support, and Why Serverless Changes Everything

Kubernetes CronJob adds concurrencyPolicy (Forbid/Allow/Replace), startingDeadlineSeconds for missed run recovery, and — since Kubernetes 1.25 — a timeZone field that classic crontab never had. Here's how cloud-native scheduling differs from traditional cron, why serverless functions with 15-minute execution limits need Step Functions for long-running jobs, how Airflow's catchup=True causes burst runs after maintenance windows, and why GitHub Actions cron is always UTC.

July 3, 2026 6 min read
Share: Facebook WhatsApp LinkedIn Email
Kubernetes CronJob vs Traditional Cron — ConcurrencyPolicy, TimeZone Support, and Why Serverless Changes Everything

A cron job that runs 0 2 * * * on a server in UTC will run at different local times depending on where your team is and what timezone your database uses — and a cron job that runs 0 2 * * * on a server in New York will skip entirely on the night that clocks spring forward, because 2:00 AM doesn't exist that night

The previous articles on this site covered cron syntax basics, production scheduling (idempotency, monitoring), how the cron daemon works, DST and the 2:30 AM problem, and timezone desync between server and database. This article addresses cron in cloud and containerized environments — specifically how Kubernetes, Docker, and serverless platforms handle scheduled jobs differently from traditional cron, and the operational patterns that make cloud-native scheduling more reliable.


Kubernetes CronJob: what changed from traditional cron

Kubernetes CronJob (previously ScheduledJob) runs containerized jobs on a cron schedule. The key differences from traditional crontab:

Concurrency policy: traditional cron has no built-in mechanism to prevent concurrent runs — if a job takes longer than its interval, multiple instances run simultaneously. Kubernetes CronJob has three policies:

spec:
  concurrencyPolicy: Forbid   # Skip next run if current is still running
  concurrencyPolicy: Allow    # Allow concurrent runs (default, matches traditional cron)
  concurrencyPolicy: Replace  # Kill current run and start a new one

Forbid is the safe default for jobs that aren't idempotent — preventing the state corruption that occurs when two instances of the same job modify the same data simultaneously.

startingDeadlineSeconds: if the Kubernetes controller misses a scheduled time (control plane downtime, cluster overload), it attempts to start the job within this window:

spec:
  startingDeadlineSeconds: 300  # Start within 5 minutes of scheduled time or skip

Without this, a missed schedule might trigger many catchup runs.


The successfulJobsHistoryLimit problem

Kubernetes CronJobs create Job objects (and associated Pods) for each run. Without cleanup configuration, these accumulate indefinitely — eventually consuming significant cluster resources or hitting Kubernetes API limits:

spec:
  successfulJobsHistoryLimit: 3    # Keep only last 3 successful Job objects
  failedJobsHistoryLimit: 1        # Keep only last 1 failed Job object

The default values (3 and 1 respectively in recent Kubernetes versions) are reasonable for most use cases. Setting to 0 deletes Job objects immediately after completion — losing the ability to inspect logs from recent runs.

The operational pattern: keep enough history to debug failures (at least 2-3 runs for failed jobs) but not so much that Jobs accumulate unbounded. For debugging, ship logs to a centralised logging system (Fluentd, Loki, Datadog) rather than relying on Pod log retention.


Serverless scheduled functions: the cold start problem

AWS EventBridge (CloudWatch Events), Google Cloud Scheduler, and Azure Scheduler trigger serverless functions on cron-like schedules. The differences from traditional cron:

Cold start latency: a serverless function that hasn't run recently may have a "cold start" delay of 100ms-2s before execution begins. For scheduled jobs, this is usually acceptable (a 2-second delay on a minute-level schedule is negligible). For latency-sensitive jobs (those that must complete before a next step begins), cold starts need to be accounted for.

Execution time limits: most serverless platforms impose execution time limits (15 minutes for AWS Lambda, 9 minutes for Google Cloud Functions, 10 minutes for Azure Functions). Long-running jobs (database maintenance, large batch exports) that exceed these limits are terminated mid-execution.

The solution for long-running scheduled jobs: break the job into multiple steps with a state machine (AWS Step Functions, Google Cloud Workflows) — the orchestrator handles state between steps, each running as a separate short-lived function.


Cron timezone specification in modern systems

Traditional cron runs in the system timezone of the server — there's no standard way to specify a timezone per job in classic crontab format.

Modern alternatives that support timezone specification:

GitHub Actions:

on:
  schedule:
    - cron: '0 9 * * 1'  # UTC only — no timezone support

GitHub Actions always runs cron in UTC — users must convert their target local time to UTC manually.

Kubernetes CronJob (Kubernetes 1.25+):

spec:
  timeZone: "Europe/London"
  schedule: "0 9 * * 1"  # 9 AM London time

The timeZone field was added in Kubernetes 1.25 (stable in 1.27) — enabling timezone-aware scheduling directly in the spec.

systemd Timer:

[Timer]
OnCalendar=Mon *-*-* 09:00:00 Europe/London

systemd timers natively support timezone specification.

Airflow: Python-based scheduling with full timezone support via pendulum — specifying timezone="Europe/London" on a DAG makes all schedule calculations timezone-aware.


The "missed run" problem and catchup behaviour

When a cron scheduler is offline (server reboot, cluster maintenance, deployment), scheduled runs may be missed. Different systems handle this differently:

Traditional cron (vixie cron): missed runs are not caught up — they're simply lost. If the server was down from 2 AM to 4 AM and you had a 3 AM job, it doesn't run until the next scheduled occurrence.

Kubernetes CronJob with startingDeadlineSeconds: will attempt to start missed runs within the deadline window. If multiple runs were missed and concurrencyPolicy is Forbid, only the most recent missed run is started.

Airflow: has configurable catchup behaviour per DAG. catchup=True runs all missed DAG runs from the start_date to the current time; catchup=False skips missed runs. For most production DAGs, catchup=False is safer — preventing a burst of catchup runs after a maintenance window.


How to use the Cron Explainer on sadiqbd.com

  1. For Kubernetes CronJob expressions: the cron format is identical to traditional cron — the explainer translates the schedule correctly; then layer in timeZone, concurrencyPolicy, and startingDeadlineSeconds separately in the Kubernetes spec
  2. For UTC-only platforms (GitHub Actions): use the explainer to verify the schedule, then convert your intended local time to UTC before pasting into the workflow file
  3. For DST-sensitive schedules: the previous DST article covered which times to avoid; the explainer shows when the job fires — check that the scheduled time doesn't fall in the missing hour (spring forward) or ambiguous hour (fall back) in the relevant timezone

Frequently Asked Questions

Should I use cron for database backups or is there a better approach in cloud environments? Managed database services provide their own backup scheduling that's more reliable than cron-based approaches. AWS RDS, Google Cloud SQL, and Azure SQL all provide automated backup scheduling with retention policies, point-in-time recovery, and cross-region replication — without any cron configuration. For custom backup requirements (specific dump formats, custom destinations, additional processing), cron-based approaches work but should use: idempotent scripts (won't corrupt data if run twice), output validation (check that the backup file is valid after creation), and alerting on failure (a silent backup failure is worse than no backup at all). Cloud-native scheduling (EventBridge/Cloud Scheduler) is more reliable than server-level cron for cloud workloads.

Is the Cron Explainer free? Yes — completely free, no sign-up required.

Try the Cron Explainer free at sadiqbd.com — translate any cron expression into plain English instantly.

Share: Facebook WhatsApp LinkedIn Email

Cron Explainer

Free, instant results — no sign-up required.

Open Cron Explainer →
Similar Tools
Hash Generator Password Generator Base64 Encoder/Decoder UUID Generator Timestamp Converter URL Encoder/Decoder Number Base Converter Random String Generator
Production Scheduled Jobs: Idempotency, Monitoring, and Modern Alternatives to Cron
Developer
Production Scheduled Jobs: Idempotency, Monitoring, and Modern Alternatives to Cron
How the Cron Daemon Works: OS Scheduling, Process Priority, and When to Use systemd Timers Instead
Developer
How the Cron Daemon Works: OS Scheduling, Process Priority, and When to Use systemd Timers Instead
Cron and Daylight Saving Time: Why Your 2:30 AM Job Didn't Run — or Ran Twice
Developer
Cron and Daylight Saving Time: Why Your 2:30 AM Job Didn't Run — or Ran Twice
Cron Doesn't Know What Timezone You Mean — The Server Timezone, Database Desync, and Kubernetes TimeZone Fix
Developer
Cron Doesn't Know What Timezone You Mean — The Server Timezone, Database Desync, and Kubernetes TimeZone Fix