StackPractices
beginner By Mathias Paulenko

Cron Jobs

How to schedule and manage recurring tasks using cron syntax across Linux, Python, and Node.js.

Topics: devops

Overview

Cron is the standard Unix job scheduler for running commands at specified intervals. Whether you need to back up databases, send emails, clean logs, or fetch data, cron provides a reliable mechanism for recurring automation.

Beyond system cron, most programming ecosystems offer scheduling libraries that bring cron-like functionality directly into your application.

When to Use

Use this recipe when:

  • Running periodic tasks on a server (backups, cleanups, reports). See Background Jobs for task queue patterns.
  • Scheduling background jobs within an application. See Scheduled Jobs for serverless cron.
  • Replacing manual processes with automated scripts. See Bash Scripting Automation for script automation.
  • Coordinating distributed job execution. See RabbitMQ Task Queue for distributed task coordination.

Solution

Linux (System Cron)

# Edit crontab
crontab -e

# Every day at 3:00 AM
0 3 * * * /usr/local/bin/backup.sh

# Every 15 minutes
*/15 * * * * /usr/local/bin/check-health.sh

# Every Monday at 9:00 AM
0 9 * * 1 /usr/local/bin/weekly-report.sh

# Every first day of the month at midnight
0 0 1 * * /usr/local/bin/monthly-cleanup.sh

Python

import schedule
import time

def job():
    print("Running scheduled task...")

# Every 10 minutes
schedule.every(10).minutes.do(job)

# Every day at 9:30 AM
schedule.every().day.at("09:30").do(job)

# Every Monday
schedule.every().monday.do(job)

while True:
    schedule.run_pending()
    time.sleep(1)

JavaScript (Node.js)

const cron = require('node-cron');

// Every 15 minutes
cron.schedule('*/15 * * * *', () => {
  console.log('Running every 15 minutes');
});

// Every day at 3:00 AM
cron.schedule('0 3 * * *', () => {
  console.log('Running daily backup');
});

// Every Monday at 9:00 AM
cron.schedule('0 9 * * 1', () => {
  console.log('Running weekly report');
});

Explanation

Cron expressions use 5 fields:

FieldAllowed ValuesDescription
Minute0-59Minute of the hour
Hour0-23Hour of the day
Day of Month1-31Day of the month
Month1-12Month of the year
Day of Week0-7 (0 and 7 = Sunday)Day of the week

Special characters:

  • * — any value
  • , — value list separator | - — range of values | | */n — every n steps |

Common Schedules

ExpressionSchedule
*/5 * * * *Every 5 minutes
0 * * * *Every hour
0 0 * * *Every day at midnight
0 9 * * 1Every Monday at 9 AM
0 0 1 * *First day of every month
0 0 * * 0Every Sunday at midnight

What Works

  • Use absolute paths for commands and scripts in crontab
  • Redirect output to a log file or /dev/null to avoid mail spam
  • Set a specific timezone if your jobs depend on business hours
  • Use a process manager (systemd, PM2) for application-level schedulers
  • Add error handling and alerting for failed scheduled tasks
  • Test expressions with online cron validators before deploying

Common Mistakes

  • Forgetting to make scripts executable (chmod +x)
  • Using relative paths that fail in cron’s minimal environment
  • Not handling overlapping job executions (use locking)
  • Ignoring daylight saving time changes
  • Running too frequent jobs without rate limiting or backoff

Performance Tips

  1. Stagger job schedules. Avoid running multiple heavy jobs at the same time:
# Bad: all at midnight
0 0 * * * /usr/local/bin/backup.sh
0 0 * * * /usr/local/bin/cleanup.sh
0 0 * * * /usr/local/bin/report.sh

# Good: stagger by 30 minutes
0 0 * * * /usr/local/bin/backup.sh
30 0 * * * /usr/local/bin/cleanup.sh
0 1 * * * /usr/local/bin/report.sh
  1. Use jitter for distributed jobs. Add random delay to prevent thundering herd:
import random
import time

def run_with_jitter(max_delay=300):
    delay = random.randint(0, max_delay)
    time.sleep(delay)
    run_job()
  1. Set timeouts. Prevent runaway jobs from consuming resources:
# Kill job after 1 hour
0 3 * * * timeout 3600 /usr/local/bin/backup.sh
# Kubernetes CronJob
spec:
  jobTemplate:
    spec:
      activeDeadlineSeconds: 3600
  1. Clean up old job artifacts. Set retention policies:
# Delete backups older than 30 days
0 4 * * * find /backup -name "*.sql" -mtime +30 -delete
# Kubernetes CronJob
spec:
  successfulJobsHistoryLimit: 3
  failedJobsHistoryLimit: 5

Frequently Asked Questions

How do I see which cron jobs are running?

Use crontab -l for the current user, or sudo cat /var/spool/cron/crontabs/ for system jobs.

Can I run cron jobs inside a Docker container?

Yes, but the container must stay running. Consider using the host's cron or an external scheduler like Kubernetes CronJobs.

What happens if a job takes longer than its interval?

By default, overlapping jobs will run concurrently. Use file locks or a job queue to prevent overlap.