How to Create and Manage Systemd Timer Units

Learn to harness the power of systemd timer units for efficient task scheduling on Linux. This guide provides a comprehensive walkthrough of creating, configuring, and managing `.timer` and `.service` units, offering practical examples for daily, hourly, and specific timed events. Discover how to enable, start, stop, and monitor your scheduled tasks using `systemctl` and `journalctl`, and understand the advantages over traditional cron jobs. Ideal for system administrators and developers seeking robust automation solutions.

38 views

Mastering Systemd Timer Units: A Comprehensive Guide

Systemd, the ubiquitous system and service manager for Linux, offers a powerful and flexible alternative to traditional cron jobs for scheduling tasks. Systemd timer units, a feature built directly into the systemd ecosystem, provide enhanced control, better integration with system services, and more granular logging capabilities. This guide will walk you through the process of creating, managing, and monitoring systemd timer units, empowering you to automate tasks with confidence and efficiency.

While cron has been the go-to for task scheduling for decades, systemd timers offer several advantages. They can be tied directly to service units, meaning a timer can activate a service only when the system is ready, or a service can be stopped if a timer expires before it completes. This tight integration simplifies complex dependency management. Furthermore, systemd's logging infrastructure (journald) provides a centralized and searchable log for all timer activities, making debugging significantly easier than sifting through scattered cron logs.

Understanding Systemd Timer Unit Structure

A systemd timer unit is always paired with a corresponding service unit (or another unit type) that it is intended to activate. The timer unit itself defines when the associated unit should be activated, while the service unit defines what action to perform. Both units typically reside in the same directory, often /etc/systemd/system/ for custom units.

A typical timer unit file has the .timer extension, and its associated service unit file has the .service extension. For example, if you want to schedule a task defined in mytask.service, you would create a mytask.timer file.

Example: mytask.timer Structure

[Unit]
Description=Run my custom task daily

[Timer]
OnCalendar=daily
Persistent=true

[Install]
WantedBy=timers.target

Let's break down the key sections:

  • [Unit] Section:

    • Description: A human-readable description of the timer. This is helpful for identification in status outputs.
  • [Timer] Section: This is the core of the timer unit, defining the scheduling.

    • OnCalendar=daily: This directive specifies when the timer should activate. daily is a shorthand for *-*-* 00:00:00. Systemd supports a wide range of calendar event specifications, similar to cron but with more flexibility. Other examples include:
      • hourly: Every hour.
      • weekly: Every week (equivalent to Mon *-*-* 00:00:00).
      • Sun *-*-* 10:00: Every Sunday at 10 AM.
      • *-*-15 14:30: On the 15th of every month at 2:30 PM.
      • Mon..Fri *-*-* 09:00: Weekdays at 9 AM.
    • Persistent=true: If this is set to true, the timer will activate as soon as possible if the event occurred while the system was off. For OnCalendar timers, this means if the system was off during the scheduled time, the timer will trigger once the system boots up and the timer becomes active.
    • OnBootSec=: Activates the timer a specified time after the system boots. For example, OnBootSec=15min would trigger 15 minutes after boot.
    • OnUnitActiveSec=: Activates the timer a specified time after the unit it activates (e.g., the service) last became active. For example, OnUnitActiveSec=1h would trigger one hour after the associated service last finished.
    • OnUnitInactiveSec=: Activates the timer a specified time after the unit it activates last became inactive.
    • AccuracySec=: Specifies the timer's accuracy. Systemd tries to wake up the system for timers only if the event is within this time window, helping to save power. Defaults to 1min.
    • RandomizedDelaySec=: Adds a random delay to the timer trigger, up to the specified duration. Useful for distributing load.
  • [Install] Section: This section defines how the timer unit can be enabled.

    • WantedBy=timers.target: This directive ensures that when the timer is enabled, it becomes part of the timers.target, which is a standard target that includes all active timers. This means the timer will start automatically on boot once enabled.

Example: mytask.service Structure

[Unit]
Description=My custom task service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/my_custom_script.sh
User=myuser
Group=mygroup

[Install]
WantedBy=multi-user.target
  • [Unit] Section:

    • Description: A description of the service.
  • [Service] Section: This defines the service itself.

    • Type=oneshot: Suitable for tasks that run once and then exit. Other types exist for long-running daemons.
    • ExecStart: The command to execute. Ensure the script has execute permissions.
    • User/Group: Specifies the user and group under which the command should run. It's good practice not to run tasks as root unless absolutely necessary.
  • [Install] Section: This section is usually present for services that should be started on boot, although for a service triggered by a timer, this might not be strictly necessary if it's only ever meant to be started by the timer.

Creating and Enabling Timer Units

Follow these steps to create and manage your systemd timer units:

  1. Create the Service Unit File: Define your task in a .service file. Place it in /etc/systemd/system/ (or ~/.config/systemd/user/ for user-specific timers).
    bash sudo nano /etc/systemd/system/mytask.service
    Paste the example service content above and save.

  2. Create the Timer Unit File: Define the schedule in a corresponding .timer file. Place it in the same directory as the service file.
    bash sudo nano /etc/systemd/system/mytask.timer
    Paste the example timer content above and save.

  3. Reload Systemd Daemon: After creating or modifying unit files, you need to tell systemd to reload its configuration.
    bash sudo systemctl daemon-reload

  4. Enable the Timer: To make the timer start automatically on boot, enable it.
    bash sudo systemctl enable mytask.timer
    Note: You do NOT enable the service file if it's solely meant to be triggered by the timer.

  5. Start the Timer: Start the timer immediately. It will then run according to its schedule.
    bash sudo systemctl start mytask.timer

Managing and Monitoring Timer Units

Systemd provides several systemctl commands to manage and monitor your timers:

  • List all timers: See all active and inactive timers.
    bash systemctl list-timers
    This command provides output like:
    NEXT LEFT LAST PASSED UNIT ACTIVATES Tue 2023-10-27 08:00:00 UTC 10h left Wed 2023-10-26 08:00:00 UTC 14h ago mytask.timer mytask.service
    This shows when the timer is scheduled to run next, how long until it runs, when it last ran, and which service it activates.

  • List timers for a specific unit: If you want to see timers related to a specific service.
    bash systemctl list-timers --all | grep mytask.service

  • Check Timer Status: Get detailed information about a specific timer.
    bash systemctl status mytask.timer
    This will show if the timer is active, when it's scheduled to run next, and recent log entries.

  • View Service Logs: To see the output and status of the task executed by the timer, check the associated service's logs.
    bash journalctl -u mytask.service
    You can also follow the logs in real-time:
    bash journalctl -f -u mytask.service

  • Stop a Timer: If you need to temporarily disable a timer.
    bash sudo systemctl stop mytask.timer

  • Disable a Timer: To prevent a timer from starting on boot and stop it if it's running.
    bash sudo systemctl disable mytask.timer

Advanced Timer Configurations

Setting Specific Intervals

Instead of daily or hourly, you can define more precise intervals:

  • Every N minutes: OnUnitActiveSec=15min (runs 15 minutes after the service last finished).
  • Specific times: OnCalendar=*-*-* 02:30:00 (runs daily at 2:30 AM).
  • Combining conditions: OnCalendar=Mon..Fri *-*-* 08:00:00 (runs weekdays at 8 AM).

Using AccuracySec for Power Saving

If your task doesn't need to run at an exact moment, consider using AccuracySec. For example, AccuracySec=5min tells systemd it's okay to wake the system up within 5 minutes of the scheduled time. This allows systemd to bundle timer events and potentially keep the system in a lower power state for longer.

[Timer]
OnCalendar=hourly
AccuracySec=5min

Persistent vs. WakeUpOn

  • Persistent=true ensures that if an OnCalendar event is missed due to the system being off, it will run once upon the next boot. This is crucial for tasks that must not be skipped.
  • WakeUpOn= (e.g., WakeUpOn=battery, WakeUpOn=ac) can be used to specify conditions under which the system should wake up for timers. This is more advanced and often used in conjunction with systemd-suspend.service.

Timers vs. Cron

Feature Systemd Timers Cron
Integration Deep integration with systemd services, targets Standalone utility
Scheduling Flexible (calendar, relative, boot-based) Primarily time-based expressions
Logging Centralized via journalctl Scattered (/var/log/syslog, /var/log/cron.log)
Error Handling Can tie actions to service failures Basic mail notifications
Dependencies Can depend on other services being active Limited
Execution Can run as specific users, groups Can run as specific users via crontab
Power Mgmt Can be optimized for power saving (AccuracySec) Less direct control

When to choose Systemd Timers:

  • When you need tighter integration with other systemd services.
  • When centralized logging and easier debugging are priorities.
  • When you require more advanced scheduling options (e.g., time since last run).
  • For tasks related to system state or power management.

When Cron might still be preferred:

  • For very simple, standalone tasks on systems not fully embracing systemd.
  • For maximum compatibility across different Linux distributions and older systems.

Troubleshooting Common Issues

  • Task not running:
    • Check timer status: systemctl status mytask.timer. Look for Active: active and Triggered... messages.
    • Check service logs: journalctl -u mytask.service. Ensure the script is executable and has no errors.
    • Verify OnCalendar syntax: Use systemd-analyze calendar 'your-calendar-string' to test.
    • Ensure the timer is enabled and started: systemctl list-timers --all.
  • Task runs too early/late:
    • Check AccuracySec and RandomizedDelaySec.
    • Ensure the system clock is accurate (timedatectl status).
  • Permission errors:
    • Confirm the User and Group specified in the .service file have the necessary permissions for the script and any files it accesses.
    • If no user is specified, it defaults to root. Be cautious with root privileges.

Conclusion

Systemd timer units offer a robust and modern approach to scheduling tasks on Linux systems. By understanding their structure, creation, and management, you can effectively automate routine operations, improve system reliability, and leverage the full power of the systemd ecosystem. Remember to always reload the daemon after changes, enable the timer for persistence, and utilize journalctl for efficient monitoring and troubleshooting.