Skip to content
Search RunEntLinux

Searches general documentation on RunEntLinux. Each distribution has its own documentation search.

    Browse this documentation

    Scheduled Tasks (Timers)

    systemd timers are a modern alternative to cron, offering more precise scheduling control, seamless log integration, and dependency management capabilities. On CentOS/AlmaLinux/Rocky Linux, an increasing number of system tasks have been migrated from cron to systemd timers.

    Featuresystemd TimerCron
    Log integrationAutomatically integrates with journald; viewable via journalctlRequires manual log redirection
    Dependency managementSupports After=, Requires=, and other dependency declarationsNo dependency management
    Missed executionsSupports Persistent=true; missed tasks run at next startupMissed tasks are lost
    Resource controlCan set CPU, memory, and IO limitsNo resource control
    PrecisionSupports microsecond-level precisionMinimum granularity is 1 minute
    Boot delaySupports OnBootSec= and other relative time triggersNot supported
    Random delaySupports RandomizedDelaySec= to spread loadNot supported
    ManagementUnified management via systemctlRequires editing crontab files

    systemd timers work in pairs: each .timer unit corresponds to a .service unit with the same name. When the timer triggers, systemd automatically starts the corresponding service unit.

    For example:

    • backup.timer — Defines the trigger schedule
    • backup.service — Defines the task to execute

    Triggered based on relative time, suitable for “how long since a certain event” scenarios:

    DirectiveDescription
    OnBootSec=Trigger after a specified time since system boot
    OnActiveSec=Trigger after a specified time since the timer was activated
    OnStartupSec=Trigger after a specified time since systemd started
    OnUnitActiveSec=Trigger after a specified time since the corresponding service was last activated
    OnUnitInactiveSec=Trigger after a specified time since the corresponding service last completed

    Triggered based on absolute time, similar to cron scheduling:

    DirectiveDescription
    OnCalendar=Trigger according to a calendar time expression

    OnCalendar= uses the following format:

    DayOfWeek Year-Month-Day Hour:Minute:Second
    ExpressionDescriptionCron Equivalent
    *-*-* 00:00:00Every day at midnight0 0 * * *
    *-*-* *:00:00Every hour on the hour0 * * * *
    *-*-* *:*:00Every minute* * * * *
    *-*-01 00:00:001st of every month at midnight0 0 1 * *
    Mon *-*-* 08:00:00Every Monday at 8:00 AM0 8 * * 1
    Mon..Fri *-*-* 18:00:00Weekdays at 6:00 PM0 18 * * 1-5
    *-*-* 06,18:00:00Every day at 6:00 AM and 6:00 PM0 6,18 * * *
    *-*-* 09:00:00/2hEvery 2 hours starting at 9:00 AM—

    systemd also provides convenient presets:

    PresetEquivalent Expression
    minutely*-*-* *:*:00
    hourly*-*-* *:00:00
    daily*-*-* 00:00:00
    weeklyMon *-*-* 00:00:00
    monthly*-*-01 00:00:00
    yearly*-01-01 00:00:00

    Use systemd-analyze calendar to verify whether an expression is correct and preview upcoming trigger times:

    Verify a time expression and view the next trigger time
    systemd-analyze calendar "Mon..Fri *-*-* 09:00:00"
    Verify an expression that triggers every 15 minutes
    systemd-analyze calendar "*-*-* *:00/15:00"

    Creating a Scheduled Task: Complete Example

    Section titled “Creating a Scheduled Task: Complete Example”

    The following example demonstrates how to create a timer + service pair using a database backup task.

    Create the backup script
    sudo vim /opt/scripts/db-backup.sh

    Enter the following content:

    /opt/scripts/db-backup.sh
    #!/bin/bash
    BACKUP_DIR="/backup/database"
    TIMESTAMP=$(date +%Y%m%d_%H%M%S)
    mkdir -p "$BACKUP_DIR"
    mysqldump --all-databases | gzip > "$BACKUP_DIR/all-db-$TIMESTAMP.sql.gz"
    # Delete backups older than 7 days
    find "$BACKUP_DIR" -name "*.sql.gz" -mtime +7 -delete
    echo "Database backup completed: all-db-$TIMESTAMP.sql.gz"
    Grant execute permission to the script
    sudo chmod +x /opt/scripts/db-backup.sh
    Create the backup service unit file
    sudo vim /etc/systemd/system/db-backup.service
    /etc/systemd/system/db-backup.service
    [Unit]
    Description=Database Backup Service
    After=mariadb.service
    Wants=mariadb.service
    [Service]
    Type=oneshot
    ExecStart=/opt/scripts/db-backup.sh
    User=root
    StandardOutput=journal
    StandardError=journal
    # Timeout setting (large database backups may take a long time)
    TimeoutStartSec=3600
    # Security hardening
    PrivateTmp=true
    ProtectHome=true

    Note: Services triggered by timers typically do not need an [Install] section, since they are started by the timer rather than directly enabled.

    Create the backup timer unit file
    sudo vim /etc/systemd/system/db-backup.timer
    /etc/systemd/system/db-backup.timer
    [Unit]
    Description=Run Database Backup Daily at 2:00 AM
    [Timer]
    OnCalendar=*-*-* 02:00:00
    RandomizedDelaySec=300
    Persistent=true
    [Install]
    WantedBy=timers.target

    Configuration details:

    DirectiveDescription
    OnCalendar=*-*-* 02:00:00Trigger every day at 2:00 AM
    RandomizedDelaySec=300Random delay of 0-300 seconds, to avoid multiple servers executing simultaneously
    Persistent=trueIf the execution time was missed (e.g., server was off), run immediately at next startup
    Reload the systemd configuration
    sudo systemctl daemon-reload
    Enable and start the timer
    sudo systemctl enable --now db-backup.timer
    View the timer status and next trigger time
    sudo systemctl status db-backup.timer
    Manually trigger the backup service for testing
    sudo systemctl start db-backup.service
    View the backup service execution logs
    sudo journalctl -u db-backup.service -n 20

    In addition to calendar-based timers, monotonic timers are suitable for “execute at regular intervals” scenarios:

    /etc/systemd/system/health-check.timer - First run 1 minute after boot, then every 5 minutes
    [Unit]
    Description=Run Health Check Every 5 Minutes
    [Timer]
    OnBootSec=1min
    OnUnitActiveSec=5min
    [Install]
    WantedBy=timers.target
    /etc/systemd/system/health-check.service
    [Unit]
    Description=System Health Check
    [Service]
    Type=oneshot
    ExecStart=/opt/scripts/health-check.sh
    List all active timers and their next trigger times
    systemctl list-timers
    List all timers (including disabled ones)
    systemctl list-timers --all
    Stop a timer (does not remove the enable)
    sudo systemctl stop db-backup.timer
    Disable and stop a timer
    sudo systemctl disable --now db-backup.timer

    If you have an existing crontab task:

    30 3 * * * /opt/scripts/cleanup.sh

    The corresponding systemd timer configuration is:

    /etc/systemd/system/cleanup.service
    [Unit]
    Description=Daily Cleanup Task
    [Service]
    Type=oneshot
    ExecStart=/opt/scripts/cleanup.sh
    /etc/systemd/system/cleanup.timer
    [Unit]
    Description=Run Cleanup Daily at 3:30 AM
    [Timer]
    OnCalendar=*-*-* 03:30:00
    Persistent=true
    [Install]
    WantedBy=timers.target
    Enable the migrated timer
    sudo systemctl daemon-reload && sudo systemctl enable --now cleanup.timer

    After confirming the timer is working correctly, remove the corresponding crontab entry:

    Edit crontab to remove the old task
    sudo crontab -e
    View detailed timer status
    sudo systemctl status db-backup.timer
    View the most recent execution result of the timer's associated service
    sudo systemctl status db-backup.service
    View all properties of the timer
    systemctl show db-backup.timer
    Verify OnCalendar expression syntax
    systemd-analyze calendar "*-*-* 02:00:00"
    View the complete logs for both the timer and service
    sudo journalctl -u db-backup.timer -u db-backup.service --since today