Introduction
Systemd Timers are a superior replacement for cron when scheduling tasks on Linux. They provide better system integration, fine-grained dependency management, and advanced options like randomized delays or persistence. This tutorial targets experienced administrators and developers looking to automate critical production processes. You'll learn how to structure complex service and timer units while avoiding common pitfalls.
Prerequisites
- Linux system with systemd 250+
- Root or sudo access
- Solid knowledge of systemd units
- Text editor (vim, nano)
- journalctl tool for debugging
Create the service file
[Unit]
Description=Backup base de données PostgreSQL
After=network.target postgresql.service
[Service]
Type=oneshot
User=postgres
ExecStart=/usr/local/bin/backup-script.sh
StandardOutput=journal
StandardError=journalThis file defines a oneshot task that runs after the network and PostgreSQL. The oneshot type is required for timers because the task is not a persistent daemon.
Create the base timer
[Unit]
Description=Timer quotidien pour backup DB
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
RandomizedDelaySec=45min
[Install]
WantedBy=timers.targetThe timer triggers the service at 3:00 AM. Persistent=true ensures missed executions run after reboot. RandomizedDelaySec adds a random delay of up to 45 minutes to avoid load spikes.
Enable and start the timer
sudo systemctl daemon-reload
sudo systemctl enable --now backup-db.timer
sudo systemctl list-timers --alldaemon-reload reloads the units. enable --now activates the timer immediately. list-timers shows the status and next scheduled execution.
Advanced timer with dependencies
[Unit]
Description=Nettoyage logs hebdomadaire
After=backup-db.timer
[Timer]
OnCalendar=Mon *-*-* 05:30:00
Persistent=true
OnBootSec=15min
AccuracySec=1h
[Install]
WantedBy=timers.targetThis timer runs after the backup and 15 minutes after boot. AccuracySec reduces precision to save CPU resources on embedded systems.
Complete backup script
#!/bin/bash
set -euo pipefail
BACKUP_DIR="/var/backups/db"
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p "$BACKUP_DIR"
pg_dumpall | gzip > "$BACKUP_DIR/full_$DATE.sql.gz"
find "$BACKUP_DIR" -name "*.gz" -mtime +30 -deleteIdempotent script with strict error handling. It automatically cleans up backups older than 30 days. Make it executable with chmod +x.
Best Practices
- Always use Persistent=true for critical tasks
- Limit RandomizedDelaySec to avoid excessive delays
- Keep service and timer in separate files
- Test with systemctl start --no-block before going to production
- Monitor with journalctl -u name.timer
Common Errors to Avoid
- Forgetting daemon-reload after modifying units
- Using Type=simple instead of oneshot for timers
- Ignoring script permissions (root vs user)
- Not enabling the timer with enable --now
Further Reading
Deepen your service management skills with our advanced Systemd training.