Understanding Cron Jobs: A Complete Guide
Cron is one of the most foundational tools in Unix and Linux system administration. Named after the Greek word for time (Chronos), cron is a time-based job scheduler that executes commands or scripts at specified intervals. From running nightly database backups to sending scheduled email reports, cron handles the automated scheduling layer for millions of production systems worldwide.
The cron daemon (crond) runs continuously in the background, checking every minute whether any scheduled jobs need to run. Job schedules are stored in a crontab (cron table) — a configuration file where each line defines one scheduled task. Users manage their own crontabs with the crontab -e command, while system-wide jobs live in /etc/cron.d/, /etc/cron.daily/, /etc/cron.hourly/, and related directories.
Cron Expression Syntax Deep Dive
A standard cron expression consists of five fields separated by spaces, each controlling a different time dimension:
- Minute (0–59): When within the hour the job runs.
0= on the hour,*/15= every 15 minutes,30= at the half hour. - Hour (0–23): The 24-hour clock hour.
0= midnight,9= 9 AM,*/2= every 2 hours. - Day of Month (1–31): Calendar day of the month.
1= 1st of month,15= 15th,*= every day. - Month (1–12): Calendar month.
1= January,12= December. Some cron implementations also accept month names (JAN, FEB, etc.). - Day of Week (0–7): Day of the week, with both 0 and 7 representing Sunday.
1= Monday,5= Friday,1-5= weekdays.
Special characters expand the expressiveness of cron syntax: * (any value), , (list separator — "1,3,5"), - (range — "1-5"), and / (step — "*/15"). The combination of these operators covers virtually every scheduling pattern needed in practice.
Kubernetes CronJobs: Cloud-Native Scheduling
Kubernetes introduced the CronJob resource as a first-class scheduling primitive for containerized workloads. Unlike traditional cron, which relies on a single host's cron daemon, Kubernetes CronJobs run within the cluster's control plane and benefit from all of Kubernetes' orchestration features: container isolation, resource limits, retry policies, distributed scheduling, and declarative configuration.
Key Kubernetes CronJob features include concurrencyPolicy (control whether overlapping runs are allowed, forbidden, or whether old runs are replaced), startingDeadlineSeconds (how long past the scheduled time a missed job can still start), successfulJobsHistoryLimit and failedJobsHistoryLimit (how many completed jobs to retain for debugging), and spec.timeZone (native timezone support since Kubernetes 1.27, eliminating the need to convert all schedules to UTC).
A well-structured Kubernetes CronJob manifest specifies resource requests and limits on the job container, sets an appropriate restartPolicy (OnFailure for jobs that should retry, Never for jobs that must run exactly once), and includes appropriate liveness probes if the job runs longer than expected. Always test CronJob schedules in a staging cluster before deploying to production.
AWS EventBridge Scheduler: Serverless Cron at Scale
AWS EventBridge Scheduler (formerly CloudWatch Events) provides a fully managed, serverless scheduling service. It executes schedules without requiring you to provision or manage cron infrastructure. EventBridge Scheduler supports three schedule types: cron-based schedules (using a 6-field cron expression with an added year field), rate-based schedules ("rate(5 minutes)", "rate(1 day)"), and one-time schedules (run once at a specific datetime).
EventBridge Scheduler's cron syntax differs from standard cron in two important ways: it uses a 6-field expression (minute, hour, day-of-month, month, day-of-week, year), and it requires that either day-of-month or day-of-week be set to ? (meaning "not specified") — you cannot specify both simultaneously. EventBridge also supports native timezone configuration at the schedule level, making it far easier to manage schedules for multi-timezone applications than traditional cron.
Best Practices for Production Cron Jobs
Idempotency is the most important property of a well-designed cron job. An idempotent job produces the same result whether it runs once or multiple times — it's safe to retry on failure. Design jobs to be idempotent by default: check whether work has already been done before doing it, use database transactions with unique constraints, and avoid side effects that can't be rolled back.
Observability: Always capture job output. Add >> /var/log/jobname.log 2>&1 to crontab entries to capture both stdout and stderr. For production systems, emit structured logs (JSON) to a centralized log aggregator (CloudWatch Logs, Datadog, Elastic). Emit metrics on job start, duration, success, and failure. Set up alerts on job failure or when jobs take longer than expected.
Overlap prevention: If a cron job can run longer than its schedule interval, it may overlap with the next invocation. Use file-based locking (flock), database advisory locks, or Redis SETNX to ensure only one instance runs at a time. In Kubernetes, set concurrencyPolicy: Forbid. In distributed systems, use a leader-election mechanism or a purpose-built distributed scheduler like Celery Beat with a database backend.
Environment isolation: Cron runs with a minimal shell environment — PATH typically includes only /usr/bin:/bin. Always use absolute paths for commands in crontab entries. Source the full environment if needed: source /etc/environment or use a wrapper script that sets up the environment before running the actual job. For secrets, use environment variables injected at runtime via a secrets manager rather than hardcoded values in the crontab.