Cron Alternatives (Systemd Timers, Anacron, More)
In this tutorial, you will learn about Cron Alternatives (Systemd Timers, Anacron, More). We cover key concepts, practical examples, and best practices to help you master this topic.
Explore cron alternatives: systemd timers for modern Linux, anacron for laptops, time-based job schedulers in Python, and when to choose each scheduling approach.
What You Learn
You will learn about systemd timers, anacron for non-24/7 systems, at for one-time scheduling, application-level schedulers like Celery Beat, and how to choose the right tool for different scheduling needs.
Why It Matters
Cron is not always the best choice. Systemd timers offer better logging, dependency management, and integration with modern Linux. Anacron handles laptops that sleep. Application schedulers provide database-backed schedules. Knowing alternatives prevents forcing the wrong tool.
Real-World Use
DodaTech uses systemd timers for system maintenance (log rotation, temp cleanup), Celery Beat for application tasks (report generation, notification dispatch), and anacron on developer laptops for local backups.
Systemd Timers
# Systemd timers consist of two files: .timer and .service
# /etc/systemd/system/daily-backup.service
# [Unit]
# Description=Daily database backup
#
# [Service]
# Type=oneshot
# ExecStart=/usr/local/bin/backup.sh
# User=backup
#
# [Install]
# WantedBy=multi-user.target
# /etc/systemd/system/daily-backup.timer
# [Unit]
# Description=Run daily backup at 3 AM
#
# [Timer]
# OnCalendar=daily
# OnCalendar=03:00:00
# Persistent=true
# RandomizedDelaySec=300
#
# [Install]
# WantedBy=timers.target
# Enable and start the timer
sudo systemctl daemon-reload
sudo systemctl enable daily-backup.timer
sudo systemctl start daily-backup.timer
# List timers
systemctl list-timers --all
# Check timer status
systemctl status daily-backup.timer
# View timer logs
journalctl -u daily-backup.service
# Manually trigger the service
sudo systemctl start daily-backup.service
Systemd Timer vs Cron Comparison
# Systemd timer advantages:
# 1. Logging: journalctl -u my-timer.service
# 2. Dependencies: After=network.target
# 3. Persistent=true catches missed runs after boot
# 4. RandomizedDelaySec prevents thundering herd
# 5. Resource control: CPUQuota, MemoryMax
# Cron advantages:
# 1. Simpler syntax: one line vs two files
# 2. More portable: works on any Unix
# 3. User crontabs without root
# 4. MAILTO for output delivery
# Systemd timer with complex schedule:
# /etc/systemd/system/custom-schedule.timer
# [Timer]
# OnCalendar=Mon..Fri 09:00:00
# OnCalendar=Sat 10:00:00
# Persistent=true
# Systemd calendar events:
# OnCalendar=hourly
# OnCalendar=daily
# OnCalendar=weekly
# OnCalendar=monthly
# OnCalendar=Mon..Fri 09:00:00
# OnCalendar=*-*-01 00:00:00 (first of month)
# OnCalendar=*:0/15 (every 15 minutes)
Anacron for Non-24/7 Systems
# Anacron runs jobs that were missed due to system downtime
# Ideal for laptops and desktops that are not always on
# /etc/anacrontab format:
# period delay job-identifier command
# 1 5 cron.daily run-parts /etc/cron.daily
# 7 10 cron.weekly run-parts /etc/cron.weekly
# 30 15 cron.monthly run-parts /etc/cron.monthly
# Period: days between runs
# Delay: minutes to wait after boot before running
# Identifier: unique name (stored in /var/spool/anacron/)
# Add a custom anacron job:
# 7 20 my-weekly-job /usr/local/bin/weekly-cleanup.sh
# Check when anacron last ran each job:
cat /var/spool/anacron/*
At Command for One-Time Scheduling
# at runs a command once at a specified time
# Unlike cron, no recurring schedules
# Schedule a one-time job
echo "/usr/local/bin/backup.sh" | at 03:00
# Schedule with date
echo "systemctl restart nginx" | at 23:00 today
echo "curl https://api.dodatech.com/deploy" | at 09:00 tomorrow
# Schedule with relative time
echo "shutdown -h now" | at now + 1 hour
echo "send_report.py" | at now + 30 minutes
# List pending at jobs
atq
# Remove a job
atrm 5 # Remove job number 5
# View at job details
at -c 5
Application-Level Scheduling
#!/usr/bin/env python3
"""Application-level scheduler using Python schedule library."""
import schedule
import time
import threading
class AppScheduler:
def __init__(self):
self.jobs = []
def everyday_at(self, time_str, func):
schedule.every().day.at(time_str).do(func)
def every_n_minutes(self, minutes, func):
schedule.every(minutes).minutes.do(func)
def on_monday(self, time_str, func):
schedule.every().monday.at(time_str).do(func)
def on_weekdays(self, time_str, func):
schedule.every().monday.at(time_str).do(func)
schedule.every().tuesday.at(time_str).do(func)
schedule.every().wednesday.at(time_str).do(func)
schedule.every().thursday.at(time_str).do(func)
schedule.every().friday.at(time_str).do(func)
def run_threaded(self):
def loop():
while True:
schedule.run_pending()
time.sleep(30)
thread = threading.Thread(target=loop, daemon=True)
thread.start()
def run_once(self):
schedule.run_pending()
def generate_report():
print("Weekly report generated")
def cache_warm():
print("Cache warmed")
scheduler = AppScheduler()
scheduler.everyday_at("03:00", lambda: print("Backup running"))
scheduler.every_n_minutes(30, cache_warm)
scheduler.on_monday("09:00", generate_report)
scheduler.run_threaded()
time.sleep(65)
Celery Beat Scheduler
# celery_app.py
from celery import Celery
from celery.schedules import crontab
app = Celery('tasks', broker='redis://localhost:6379')
app.conf.beat_schedule = {
'add-every-30-seconds': {
'task': 'tasks.add',
'schedule': 30.0,
'args': (16, 16),
},
'daily-report': {
'task': 'tasks.generate_report',
'schedule': crontab(hour=9, minute=0),
},
'weekly-cleanup': {
'task': 'tasks.cleanup',
'schedule': crontab(hour=2, minute=0, day_of_week=0),
},
'monthly-billing': {
'task': 'tasks.run_billing',
'schedule': crontab(0, 0, day_of_month='1'),
},
}
@app.task
def add(x, y):
return x + y
@app.task
def generate_report():
return {'report': 'generated'}
@app.task
def cleanup():
return {'cleaned': True}
@app.task
def run_billing():
return {'billing': 'completed'}
Choosing the Right Scheduler
schedulers = {
'cron': {
'best_for': 'Simple recurring tasks on always-on servers',
'pros': 'Universal, simple syntax, no dependencies',
'cons': 'No dependency management, minimal logging',
},
'systemd_timer': {
'best_for': 'System-level tasks on modern Linux',
'pros': 'Journal logging, dependencies, resource control',
'cons': 'Linux only, two-file setup',
},
'anacron': {
'best_for': 'Laptops and desktops that sleep',
'pros': 'Runs missed jobs after downtime',
'cons': 'Daily granularity only',
},
'celery_beat': {
'best_for': 'Application tasks with database integration',
'pros': 'Dynamic schedules, distributed execution',
'cons': 'Requires Redis/RabbitMQ, complex setup',
},
'kubernetes_cronjob': {
'best_for': 'Containerized workloads in Kubernetes',
'pros': 'Declarative, self-healing, scalable',
'cons': 'Requires Kubernetes cluster',
},
}
for name, info in schedulers.items():
print(f"{name:20s}")
print(f" Best for: {info['best_for']}")
print(f" Pros: {info['pros']}")
print(f" Cons: {info['cons']}")
print()
Common Mistakes
1. Using Cron for One-Time Jobs
Cron only does recurring schedules. Use at for one-time jobs. Do not create a cron job and then delete it.
2. Ignoring Systemd Timers on Modern Systems
Systemd timers provide better integration than cron for system-level tasks. Journalctl gives you structured logging automatically.
3. Using Cron on Laptops
Laptops sleep and may miss Cron Jobs. Use anacron or systemd timers with Persistent=true for non-24/7 devices.
4. Application Scheduler Without Persistence
In-memory schedulers lose schedules on restart. Use database-backed schedulers like Celery Beat for production.
5. Mixing System and Application Schedules
System tasks (log rotation, temp files) belong in system schedulers (cron, systemd). Application tasks belong in application schedulers (Celery Beat).
Practice Questions
1. What is the main advantage of systemd timers over cron?
Integrated logging with journalctl, dependency management (After=network.target), resource control (CPUQuota, MemoryMax), and persistent missed-run detection.
2. When should you use anacron instead of cron?
On systems that are not always running, like laptops. Anacron runs missed jobs after the system powers on.
3. What is Celery Beat?
A database-backed scheduler for Celery that supports dynamic schedule changes at runtime without restarting workers.
4. How do you schedule a one-time job in Linux?
Use the at command: echo "command" | at 03:00. The job runs once at the specified time and is removed.
Challenge
Design a scheduling Strategy for a web application on a laptop used for development: system maintenance logs (use systemd timers), daily database backup (anacron with 1-hour delay after boot), cache warming every 30 minutes (application scheduler with persistence), deployment tasks (at command for one-time use).
FAQ
Mini Project: Systemd Timer Setup
# Create a systemd service and timer for log cleanup
# /etc/systemd/system/log-cleanup.service
cat > /etc/systemd/system/log-cleanup.service << 'EOF'
[Unit]
Description=Clean old log files
After=local-fs.target
[Service]
Type=oneshot
ExecStart=/usr/bin/find /var/log -name "*.log" -mtime +30 -delete
ExecStart=/usr/bin/journalctl --vacuum-time=30d
User=root
StandardOutput=journal
EOF
# /etc/systemd/system/log-cleanup.timer
cat > /etc/systemd/system/log-cleanup.timer << 'EOF'
[Unit]
Description=Run log cleanup daily
Requires=log-cleanup.service
[Timer]
OnCalendar=daily
Persistent=true
RandomizedDelaySec=600
[Install]
WantedBy=timers.target
EOF
# Enable and start
sudo systemctl daemon-reload
sudo systemctl enable log-cleanup.timer
sudo systemctl start log-cleanup.timer
# Verify
systemctl list-timers log-cleanup.timer
journalctl -u log-cleanup.service
What's Next
Now that you understand cron alternatives, explore cron monitoring best practices, then learn about cron health checks for ensuring jobs run successfully.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro