{"id":72493,"date":"2026-03-25T14:07:17","date_gmt":"2026-03-25T11:07:17","guid":{"rendered":"https:\/\/cloudspinx.com\/?p=72493"},"modified":"2026-03-25T14:07:35","modified_gmt":"2026-03-25T11:07:35","slug":"systemd-timers-linux","status":"publish","type":"post","link":"https:\/\/computingforgeeks.com\/systemd-timers-linux\/","title":{"rendered":"Configure Systemd Timers on Linux (Practical Examples)"},"content":{"rendered":"\n<p>Systemd timers do everything cron does, plus some things cron cannot: they log to the journal, they can catch up on missed runs after a reboot, they support randomized delays to avoid thundering herds, and you can test them with <code>systemctl start<\/code> without waiting for the schedule to trigger. If your server runs systemd (which is every major distro since 2015), you already have timers available.<\/p>\n\n\n\n<p>This guide covers creating systemd timers from scratch on Ubuntu 24.04, with practical examples you can adapt: disk monitoring, automated backups, log cleanup, user-level timers, and transient one-off timers. Every command and output below was tested on a real VM. For background on <a href=\"https:\/\/computingforgeeks.com\/systemctl-commands-linux\/\" target=\"_blank\" rel=\"noreferrer noopener\">managing systemd services with systemctl<\/a>, see our reference guide.<\/p>\n\n\n\n<p><em>Tested <strong>March 2026<\/strong> on Ubuntu 24.04 LTS with systemd 255<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How Systemd Timers Work<\/h2>\n\n\n\n<p>A systemd timer consists of two unit files that work together:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A <code>.timer<\/code> unit that defines the schedule (when to run)<\/li>\n\n<li>A <code>.service<\/code> unit that defines the task (what to run)<\/li>\n<\/ul>\n\n\n\n<p>The timer activates the service when the schedule triggers. By default, a timer named <code>backup.timer<\/code> activates <code>backup.service<\/code> (matching name, different suffix). Both files go in <code>\/etc\/systemd\/system\/<\/code> for system-wide timers.<\/p>\n\n\n\n<p>There are two types of timers:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Type<\/th><th>Trigger<\/th><th>Example<\/th><\/tr><\/thead><tbody><tr><td><strong>Monotonic<\/strong><\/td><td>Relative to an event (boot, last run)<\/td><td><code>OnBootSec=5min<\/code>, <code>OnUnitActiveSec=1h<\/code><\/td><\/tr><tr><td><strong>Calendar<\/strong><\/td><td>At specific dates\/times<\/td><td><code>OnCalendar=*-*-* 02:00:00<\/code> (daily at 2am)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Monotonic timers run relative to when the system booted or when the service last ran. Calendar timers run at specific wall-clock times, like cron.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Example 1: Disk Usage Monitor (Every 5 Minutes)<\/h2>\n\n\n\n<p>This timer checks root partition usage every 5 minutes and logs a warning when it exceeds 80%. It demonstrates a monotonic timer with <code>OnUnitActiveSec<\/code>.<\/p>\n\n\n\n<p>Create the script that does the actual work:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo tee \/usr\/local\/bin\/disk-monitor.sh > \/dev\/null << 'EOF'\n#!\/bin\/bash\nUSAGE=$(df -h \/ | awk 'NR==2 {print $5}' | tr -d '%')\nTIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')\necho \"$TIMESTAMP - Root partition usage: ${USAGE}%\" >> \/var\/log\/disk-monitor.log\nif [ \"$USAGE\" -gt 80 ]; then\n    echo \"$TIMESTAMP - WARNING: Disk usage above 80%!\" >> \/var\/log\/disk-monitor.log\nfi\nEOF\nsudo chmod +x \/usr\/local\/bin\/disk-monitor.sh<\/code><\/pre>\n\n\n\n<p>Create the service unit that runs the script:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo tee \/etc\/systemd\/system\/disk-monitor.service > \/dev\/null << 'EOF'\n[Unit]\nDescription=Monitor disk usage and log alerts\n\n[Service]\nType=oneshot\nExecStart=\/usr\/local\/bin\/disk-monitor.sh\nEOF<\/code><\/pre>\n\n\n\n<p>The <code>Type=oneshot<\/code> tells systemd the service runs once and exits (not a long-running daemon). This is the correct type for timer-triggered tasks.<\/p>\n\n\n\n<p>Create the timer unit:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo tee \/etc\/systemd\/system\/disk-monitor.timer > \/dev\/null << 'EOF'\n[Unit]\nDescription=Run disk monitor every 5 minutes\n\n[Timer]\nOnBootSec=60\nOnUnitActiveSec=5min\nAccuracySec=1s\n\n[Install]\nWantedBy=timers.target\nEOF<\/code><\/pre>\n\n\n\n<p><code>OnBootSec=60<\/code> runs the first check 60 seconds after boot. <code>OnUnitActiveSec=5min<\/code> repeats every 5 minutes after each run. <code>AccuracySec=1s<\/code> ensures the timer fires within 1 second of the scheduled time (the default is 1 minute, which batches timers for power efficiency).<\/p>\n\n\n\n<p>Reload systemd, enable, and start the timer:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo systemctl daemon-reload\nsudo systemctl enable --now disk-monitor.timer<\/code><\/pre>\n\n\n\n<p>Verify the timer is active and scheduled:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>systemctl status disk-monitor.timer<\/code><\/pre>\n\n\n\n<p>The output shows when the next trigger will fire:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\u25cf disk-monitor.timer - Run disk monitor every 5 minutes\n     Loaded: loaded (\/etc\/systemd\/system\/disk-monitor.timer; enabled; preset: enabled)\n     Active: active (waiting) since Wed 2026-03-25 11:02:37 UTC; 9ms ago\n    Trigger: Wed 2026-03-25 11:07:45 UTC; 4min left\n   Triggers: \u25cf disk-monitor.service<\/code><\/pre>\n\n\n\n<p>Test the service manually without waiting for the timer:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo systemctl start disk-monitor.service\ncat \/var\/log\/disk-monitor.log<\/code><\/pre>\n\n\n\n<p>The log confirms it ran:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>2026-03-25 11:02:37 - Root partition usage: 11%<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Example 2: Daily Backup at 2 AM (Calendar Timer)<\/h2>\n\n\n\n<p>This timer runs a backup script every day at 2:00 AM. It uses <code>OnCalendar<\/code> for wall-clock scheduling, <code>Persistent=true<\/code> to catch up if the server was off at 2 AM, and <code>RandomizedDelaySec<\/code> to avoid all servers hitting the backup target at exactly the same second.<\/p>\n\n\n\n<p>Create the backup script:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo tee \/usr\/local\/bin\/daily-backup.sh > \/dev\/null << 'EOF'\n#!\/bin\/bash\nBACKUP_DIR=\"\/var\/backups\/app\"\nTIMESTAMP=$(date '+%Y%m%d_%H%M%S')\nmkdir -p \"$BACKUP_DIR\"\ntar czf \"$BACKUP_DIR\/etc-backup-${TIMESTAMP}.tar.gz\" \/etc\/hostname \/etc\/hosts 2>\/dev\/null\necho \"$(date '+%Y-%m-%d %H:%M:%S') - Backup completed: etc-backup-${TIMESTAMP}.tar.gz\" >> \/var\/log\/backup.log\n# Keep only last 7 backups\nls -t \"$BACKUP_DIR\"\/etc-backup-*.tar.gz 2>\/dev\/null | tail -n +8 | xargs rm -f 2>\/dev\/null\nEOF\nsudo chmod +x \/usr\/local\/bin\/daily-backup.sh<\/code><\/pre>\n\n\n\n<p>Create the service unit:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo tee \/etc\/systemd\/system\/daily-backup.service > \/dev\/null << 'EOF'\n[Unit]\nDescription=Daily backup of critical configs\n\n[Service]\nType=oneshot\nExecStart=\/usr\/local\/bin\/daily-backup.sh\nEOF<\/code><\/pre>\n\n\n\n<p>Create the timer with calendar scheduling:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo tee \/etc\/systemd\/system\/daily-backup.timer > \/dev\/null << 'EOF'\n[Unit]\nDescription=Run daily backup at 2:00 AM\n\n[Timer]\nOnCalendar=*-*-* 02:00:00\nPersistent=true\nRandomizedDelaySec=300\n\n[Install]\nWantedBy=timers.target\nEOF<\/code><\/pre>\n\n\n\n<p><code>Persistent=true<\/code> is the key difference from cron. If the server was powered off at 2 AM, systemd will run the backup immediately after the next boot. Cron would just skip it. <code>RandomizedDelaySec=300<\/code> adds a random delay of up to 5 minutes, which prevents all servers in a fleet from starting their backups at the exact same second.<\/p>\n\n\n\n<p>Enable and verify:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo systemctl daemon-reload\nsudo systemctl enable --now daily-backup.timer\nsystemctl status daily-backup.timer<\/code><\/pre>\n\n\n\n<p>The timer shows the next trigger time with the randomized delay applied:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\u25cf daily-backup.timer - Run daily backup at 2:00 AM\n     Loaded: loaded (\/etc\/systemd\/system\/daily-backup.timer; enabled; preset: enabled)\n     Active: active (waiting) since Wed 2026-03-25 11:02:53 UTC\n    Trigger: Thu 2026-03-26 02:02:27 UTC; 14h left\n   Triggers: \u25cf daily-backup.service<\/code><\/pre>\n\n\n\n<p>Test it manually:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo systemctl start daily-backup.service\ncat \/var\/log\/backup.log<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>2026-03-25 11:02:53 - Backup completed: etc-backup-20260325_110253.tar.gz<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Example 3: Weekly Log Cleanup (Low Priority)<\/h2>\n\n\n\n<p>Maintenance tasks like log cleanup should run at low priority so they do not compete with production workloads. This timer demonstrates <code>Nice=19<\/code> and <code>IOSchedulingClass=idle<\/code> to minimize system impact.<\/p>\n\n\n\n<p>Create the cleanup script:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo tee \/usr\/local\/bin\/log-cleanup.sh > \/dev\/null << 'EOF'\n#!\/bin\/bash\n# Remove compressed logs older than 30 days\nfind \/var\/log -name \"*.log.gz\" -mtime +30 -delete 2>\/dev\/null\nfind \/var\/log -name \"*.log.[0-9]\" -mtime +30 -delete 2>\/dev\/null\n\n# Truncate logs larger than 100MB\nfind \/var\/log -name \"*.log\" -size +100M -exec truncate -s 0 {} \\; 2>\/dev\/null\n\n# Clean systemd journal older than 7 days\njournalctl --vacuum-time=7d --quiet 2>\/dev\/null\n\necho \"$(date '+%Y-%m-%d %H:%M:%S') - Log cleanup completed\" >> \/var\/log\/cleanup.log\nEOF\nsudo chmod +x \/usr\/local\/bin\/log-cleanup.sh<\/code><\/pre>\n\n\n\n<p>Create the service with low CPU and I\/O priority:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo tee \/etc\/systemd\/system\/log-cleanup.service > \/dev\/null << 'EOF'\n[Unit]\nDescription=Clean old log files\n\n[Service]\nType=oneshot\nExecStart=\/usr\/local\/bin\/log-cleanup.sh\nNice=19\nIOSchedulingClass=idle\nEOF<\/code><\/pre>\n\n\n\n<p><code>Nice=19<\/code> gives the process the lowest CPU priority. <code>IOSchedulingClass=idle<\/code> means it only does disk I\/O when nothing else needs the disk. These settings are not available with cron.<\/p>\n\n\n\n<p>Create the timer to run every Sunday at 3 AM:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo tee \/etc\/systemd\/system\/log-cleanup.timer > \/dev\/null << 'EOF'\n[Unit]\nDescription=Weekly log cleanup\n\n[Timer]\nOnCalendar=Sun *-*-* 03:00:00\nPersistent=true\nRandomizedDelaySec=1h\n\n[Install]\nWantedBy=timers.target\nEOF<\/code><\/pre>\n\n\n\n<p>Enable and test:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo systemctl daemon-reload\nsudo systemctl enable --now log-cleanup.timer\nsudo systemctl start log-cleanup.service\nsystemctl status log-cleanup.service<\/code><\/pre>\n\n\n\n<p>The service exits cleanly with <code>status=0\/SUCCESS<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\u25cb log-cleanup.service - Clean old log files\n     Loaded: loaded (\/etc\/systemd\/system\/log-cleanup.service; static)\n     Active: inactive (dead) since Wed 2026-03-25 11:03:57 UTC\nTriggeredBy: \u25cf log-cleanup.timer\n    Process: 1934 ExecStart=\/usr\/local\/bin\/log-cleanup.sh (code=exited, status=0\/SUCCESS)\n   Main PID: 1934 (code=exited, status=0\/SUCCESS)\n        CPU: 12ms<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Example 4: Transient Timer (No Files Needed)<\/h2>\n\n\n\n<p>Sometimes you need a quick one-off scheduled task without creating permanent unit files. <code>systemd-run<\/code> creates transient timers on the fly:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo systemd-run --on-active=30s --unit=quick-task \/usr\/local\/bin\/disk-monitor.sh<\/code><\/pre>\n\n\n\n<p>This runs <code>disk-monitor.sh<\/code> once, 30 seconds from now. The timer and service are created automatically and cleaned up after execution. You can verify it was scheduled:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>systemctl list-timers quick-task*<\/code><\/pre>\n\n\n\n<p>Other useful <code>systemd-run<\/code> patterns:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Run a command at a specific time today\nsudo systemd-run --on-calendar=\"2026-03-25 15:00:00\" \/usr\/local\/bin\/daily-backup.sh\n\n# Run a command every 10 minutes (persists until reboot)\nsudo systemd-run --on-active=10min --on-unit-active=10min \/usr\/local\/bin\/disk-monitor.sh\n\n# Run with a description for easier identification\nsudo systemd-run --on-active=5min --description=\"One-off DB export\" pg_dump mydb > \/tmp\/export.sql<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Example 5: User Timer (No Root Required)<\/h2>\n\n\n\n<p>User timers run under a regular user account without sudo. The unit files go in <code>~\/.config\/systemd\/user\/<\/code> instead of <code>\/etc\/systemd\/system\/<\/code>. This is useful for personal automation like syncing files or checking for updates.<\/p>\n\n\n\n<p>Create the user service directory and files:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir -p ~\/.config\/systemd\/user\/\n\ntee ~\/.config\/systemd\/user\/user-task.service > \/dev\/null << 'EOF'\n[Unit]\nDescription=User-level task example\n\n[Service]\nType=oneshot\nExecStart=\/bin\/bash -c 'echo \"User timer ran at $(date)\" >> %h\/user-timer.log'\nEOF\n\ntee ~\/.config\/systemd\/user\/user-task.timer > \/dev\/null << 'EOF'\n[Unit]\nDescription=Run user task every 2 minutes\n\n[Timer]\nOnBootSec=30\nOnUnitActiveSec=2min\n\n[Install]\nWantedBy=timers.target\nEOF<\/code><\/pre>\n\n\n\n<p>The <code>%h<\/code> specifier expands to the user's home directory. Enable and start with the <code>--user<\/code> flag:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>systemctl --user daemon-reload\nsystemctl --user enable --now user-task.timer\nsystemctl --user status user-task.timer<\/code><\/pre>\n\n\n\n<p>The timer runs under your user account:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\u25cf user-task.timer - Run user task every 2 minutes\n     Loaded: loaded (\/home\/ubuntu\/.config\/systemd\/user\/user-task.timer; enabled; preset: enabled)\n     Active: active (running) since Wed 2026-03-25 11:03:10 UTC\n    Trigger: n\/a\n   Triggers: \u25cf user-task.service<\/code><\/pre>\n\n\n\n<p>For user timers to run when you are not logged in, enable lingering for your account:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo loginctl enable-linger $USER<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">OnCalendar Syntax Reference<\/h2>\n\n\n\n<p>The <code>OnCalendar<\/code> directive uses the format <code>DayOfWeek Year-Month-Day Hour:Minute:Second<\/code>. All fields are optional except at least one time component. The <a href=\"https:\/\/www.freedesktop.org\/software\/systemd\/man\/latest\/systemd.time.html\" target=\"_blank\" rel=\"noreferrer noopener\">systemd.time documentation<\/a> has the full specification.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Expression<\/th><th>When It Runs<\/th><\/tr><\/thead><tbody><tr><td><code>*-*-* *:00\/15:00<\/code><\/td><td>Every 15 minutes<\/td><\/tr><tr><td><code>hourly<\/code><\/td><td>Every hour at :00<\/td><\/tr><tr><td><code>daily<\/code><\/td><td>Every day at midnight<\/td><\/tr><tr><td><code>*-*-* 02:00:00<\/code><\/td><td>Every day at 2:00 AM<\/td><\/tr><tr><td><code>weekly<\/code><\/td><td>Every Monday at midnight<\/td><\/tr><tr><td><code>Mon *-*-* 09:00:00<\/code><\/td><td>Every Monday at 9:00 AM<\/td><\/tr><tr><td><code>Mon..Fri *-*-* 18:00:00<\/code><\/td><td>Weekdays at 6:00 PM<\/td><\/tr><tr><td><code>*-*-01 03:00:00<\/code><\/td><td>First of every month at 3:00 AM<\/td><\/tr><tr><td><code>*-01,04,07,10-01 00:00:00<\/code><\/td><td>Quarterly (Jan, Apr, Jul, Oct 1st)<\/td><\/tr><tr><td><code>Sun *-*-* 03:00:00<\/code><\/td><td>Every Sunday at 3:00 AM<\/td><\/tr><tr><td><code>monthly<\/code><\/td><td>First of every month at midnight<\/td><\/tr><tr><td><code>yearly<\/code><\/td><td>January 1st at midnight<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Validate any expression before deploying with <code>systemd-analyze calendar<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>systemd-analyze calendar \"Mon..Fri *-*-* 18:00:00\"<\/code><\/pre>\n\n\n\n<p>The output shows the normalized form and the next trigger time:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Normalized form: Mon..Fri *-*-* 18:00:00\n    Next elapse: Wed 2026-03-25 18:00:00 UTC\n       From now: 6h left<\/code><\/pre>\n\n\n\n<p>This catches syntax errors before they cause a timer to never fire. Always test expressions with <code>systemd-analyze calendar<\/code> first.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Timer Configuration Reference<\/h2>\n\n\n\n<p>Key directives for the <code>[Timer]<\/code> section:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Directive<\/th><th>Purpose<\/th><th>Example<\/th><\/tr><\/thead><tbody><tr><td><code>OnBootSec<\/code><\/td><td>Run N seconds\/minutes after boot<\/td><td><code>OnBootSec=5min<\/code><\/td><\/tr><tr><td><code>OnUnitActiveSec<\/code><\/td><td>Repeat N after each run<\/td><td><code>OnUnitActiveSec=1h<\/code><\/td><\/tr><tr><td><code>OnCalendar<\/code><\/td><td>Wall-clock schedule<\/td><td><code>OnCalendar=daily<\/code><\/td><\/tr><tr><td><code>Persistent<\/code><\/td><td>Catch up missed runs after downtime<\/td><td><code>Persistent=true<\/code><\/td><\/tr><tr><td><code>RandomizedDelaySec<\/code><\/td><td>Add random delay to avoid thundering herd<\/td><td><code>RandomizedDelaySec=5min<\/code><\/td><\/tr><tr><td><code>AccuracySec<\/code><\/td><td>Timer precision (default 1min)<\/td><td><code>AccuracySec=1s<\/code><\/td><\/tr><tr><td><code>OnStartupSec<\/code><\/td><td>Run N after systemd starts (user timers)<\/td><td><code>OnStartupSec=30<\/code><\/td><\/tr><tr><td><code>OnUnitInactiveSec<\/code><\/td><td>Run N after service becomes inactive<\/td><td><code>OnUnitInactiveSec=30min<\/code><\/td><\/tr><tr><td><code>Unit<\/code><\/td><td>Override which service to trigger<\/td><td><code>Unit=other.service<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">List and Monitor Timers<\/h2>\n\n\n\n<p>View all active timers on the system:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>systemctl list-timers<\/code><\/pre>\n\n\n\n<p>The output shows the next trigger time, time until trigger, last run, and which service each timer activates:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>NEXT                            LEFT    LAST                         PASSED  UNIT               ACTIVATES\nWed 2026-03-25 11:07:45 UTC 3min 48s    Wed 2026-03-25 11:02:45 UTC 1min ago disk-monitor.timer disk-monitor.service\nThu 2026-03-26 02:02:01 UTC      14h    -                                 -  daily-backup.timer daily-backup.service\nSun 2026-03-29 03:08:26 UTC   3 days    -                                 -  log-cleanup.timer  log-cleanup.service<\/code><\/pre>\n\n\n\n<p>Include inactive timers with <code>--all<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>systemctl list-timers --all<\/code><\/pre>\n\n\n\n<p>Check the journal for timer-triggered service runs:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>journalctl -u disk-monitor.service --no-pager -n 10<\/code><\/pre>\n\n\n\n<p>The journal shows exact start\/finish times and exit status for every run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Mar 25 11:02:45 ubuntu systemd[1]: Starting disk-monitor.service - Monitor disk usage and log alerts...\nMar 25 11:02:45 ubuntu systemd[1]: disk-monitor.service: Deactivated successfully.\nMar 25 11:02:45 ubuntu systemd[1]: Finished disk-monitor.service - Monitor disk usage and log alerts.<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Stop and Disable Timers<\/h2>\n\n\n\n<p>Stop a running timer (it will not fire again until manually started or re-enabled after reboot):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo systemctl stop disk-monitor.timer<\/code><\/pre>\n\n\n\n<p>Disable it so it does not start on boot:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo systemctl disable disk-monitor.timer<\/code><\/pre>\n\n\n\n<p>Remove the timer and service files entirely:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo systemctl stop disk-monitor.timer\nsudo systemctl disable disk-monitor.timer\nsudo rm \/etc\/systemd\/system\/disk-monitor.timer \/etc\/systemd\/system\/disk-monitor.service\nsudo systemctl daemon-reload<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Systemd Timers vs Cron<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Feature<\/th><th>Systemd Timers<\/th><th>Cron<\/th><\/tr><\/thead><tbody><tr><td>Catch up missed runs<\/td><td>Yes (<code>Persistent=true<\/code>)<\/td><td>No (missed = skipped)<\/td><\/tr><tr><td>Logging<\/td><td>Journald (structured, queryable)<\/td><td>Email or syslog<\/td><\/tr><tr><td>Test without waiting<\/td><td><code>systemctl start service<\/code><\/td><td>Not possible<\/td><\/tr><tr><td>Random delay<\/td><td><code>RandomizedDelaySec<\/code><\/td><td>Manual <code>sleep $RANDOM<\/code><\/td><\/tr><tr><td>CPU\/IO priority<\/td><td><code>Nice=<\/code>, <code>IOSchedulingClass=<\/code><\/td><td>Must set in script<\/td><\/tr><tr><td>Resource limits<\/td><td>cgroups (MemoryMax, CPUQuota)<\/td><td>None built-in<\/td><\/tr><tr><td>Dependencies<\/td><td><code>After=<\/code>, <code>Requires=<\/code><\/td><td>None<\/td><\/tr><tr><td>Configuration<\/td><td>Two files (.timer + .service)<\/td><td>One line in crontab<\/td><\/tr><tr><td>Second precision<\/td><td>Yes<\/td><td>Minute only<\/td><\/tr><tr><td>User-level tasks<\/td><td><code>systemctl --user<\/code><\/td><td><code>crontab -e<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Cron is still the faster option for simple, single-line scheduled commands. When you need logging, missed-run recovery, resource controls, or dependency ordering, <a href=\"https:\/\/computingforgeeks.com\/persistent-systemd-journal-linux\/\" target=\"_blank\" rel=\"noreferrer noopener\">systemd timers with persistent journal storage<\/a> are the better choice.<\/p>\n\n","protected":false},"excerpt":{"rendered":"<p>Systemd timers do everything cron does, plus some things cron cannot: they log to the journal, they can catch up on missed runs after a reboot, they support randomized delays to avoid thundering herds, and you can test them with systemctl start without waiting for the schedule to trigger. If your server runs systemd (which &#8230; <a title=\"Configure Systemd Timers on Linux (Practical Examples)\" class=\"read-more\" href=\"https:\/\/computingforgeeks.com\/systemd-timers-linux\/\" aria-label=\"Read more about Configure Systemd Timers on Linux (Practical Examples)\">Read more<\/a><\/p>\n","protected":false},"author":3,"featured_media":164480,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[299,50],"tags":[39355,39702],"class_list":["post-72493","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-how-to","category-linux-tutorials","tag-cron-jobs","tag-systemd-timers"],"_links":{"self":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts\/72493","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/comments?post=72493"}],"version-history":[{"count":2,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts\/72493\/revisions"}],"predecessor-version":[{"id":164479,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts\/72493\/revisions\/164479"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/media\/164480"}],"wp:attachment":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/media?parent=72493"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/categories?post=72493"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/tags?post=72493"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}