# systemd/cron functionality

Related articles

- systemd
- systemd/User
- systemd/Services
- systemd FAQ
- cron

Systemd is capable of taking on a significant subset of the functionality of Cron through built in support for calendar time events (from systemd version 197) as well as monotonic time events. As of systemd version 212, it also has the foundations for being an anacron replacement through the use of the `Persistent` and `OnCalendar` options in timers.

## Introduction

While Cron has been a stalwart on the Linux landscape for years, it still provides no way to detect job failures, establish job dependencies, or allocate processes to cgroups. If you require any of this functionality, systemd provides a good structure to set up job scheduling. While doing so is slightly more cumbersome than relying on dcron or cronie, the benefits are not insignificant:

- Last status and logging outputs can be got through journalctl. This enables proper debugging
- Systemd has a lot of options which are useful for setting the environment for the job to be done properly (eg IOSchedulingPriority, Nice or JobTimeoutSec)
- These jobs can be made to depend on other systemd units if required

## Hourly, daily, weekly, monthly and yearly events

One strategy which can be used for recreating this functionality is through timers which call in targets. All services which need to be run hourly can be called in as dependencies of these targets. The strategy mentioned here has been detailed first in this blogpost.

Note: There is an AUR package systemd-cron which uses a slightly different strategy to do what is being done here. If you wish to use this package, then the following scripts might need to be modified and their locations changed for them to work properly.
Note: There is also an AUR package systemd-crontab-generator which is intended to be a drop-in replacement for cron and anacron daemons. It works by parsing crontab files in known directories (like /etc/crontab and /var/spool/cron/) and generating timers and services in systemd. Though it is a beta product (while it works on several hosts owned by program's author), so it is not quite ready for production. Please read comments carefully before installation.

First, the creation of a few directories is required:

    # mkdir /etc/systemd/system/timer-{hourly,daily,weekly,monthly,yearly}.target.wants

The following files will need to be created in the paths specified in order for this to work.

### Hourly events

    /etc/systemd/system/timer-hourly.timer

    [Unit]
    Description=Hourly Timer

    [Timer]
    OnBootSec=5min
    OnCalendar=hourly
    Unit=timer-hourly.target

    [Install]
    WantedBy=basic.target

    /etc/systemd/system/timer-hourly.target

    [Unit]
    Description=Hourly Timer Target
    StopWhenUnneeded=yes

### Daily events

    /etc/systemd/system/timer-daily.timer

    [Unit]
    Description=Daily Timer

    [Timer]
    OnCalendar=daily
    Persistent=true
    Unit=timer-daily.target

    [Install]
    WantedBy=basic.target

    /etc/systemd/system/timer-daily.target

    [Unit]
    Description=Daily Timer Target
    StopWhenUnneeded=yes

As of systemd 212, the functionality of anacron is implemented in any timer which utilizes the `OnCalendar` option through the use of the `Persistent` option. If you would like to understand this functionality better, please see the `systemd.timer(5)` man page.

### Weekly events

    /etc/systemd/system/timer-weekly.timer

    [Unit]
    Description=Weekly Timer

    [Timer]
    OnCalendar=weekly
    Persistent=true
    Unit=timer-weekly.target

    [Install]
    WantedBy=basic.target

    /etc/systemd/system/timer-weekly.target

    [Unit]
    Description=Weekly Timer Target
    StopWhenUnneeded=yes

### Monthly events

    /etc/systemd/system/timer-monthly.timer

    [Unit]
    Description=Monthly Timer

    [Timer]
    OnCalendar=monthly
    Persistent=true
    Unit=timer-monthly.target

    [Install]
    WantedBy=basic.target

    /etc/systemd/system/timer-monthly.target

    [Unit]
    Description=Monthly Timer Target
    StopWhenUnneeded=yes

### Yearly events

    /etc/systemd/system/timer-yearly.timer

    [Unit]
    Description=Yearly Timer

    [Timer]
    OnCalendar=yearly
    Persistent=true
    Unit=timer-yearly.target

    [Install]
    WantedBy=basic.target

    /etc/systemd/system/timer-yearly.target

    [Unit]
    Description=Yearly Timer Target
    StopWhenUnneeded=yes

### Adding events

Adding events to these targets is as easy as dropping them into the correct wants folder. So if you wish for a particular job to take place daily, create a systemd service file.

For example, if you wish to run `foo.service` daily (which runs program bar), you would create the following file:

    /etc/systemd/system/foo.service

    [Unit]
    Description=Starts program bar
    Wants=timer-daily.timer

    [Service]
    User=                                          # Add a user if you wish the service to be executes as a particular user, else delete this line
    Type=                                          # Simple by default, change it if you know what you are doing, else delete this line
    Nice=19
    IOSchedulingClass=2
    IOSchedulingPriority=7
    ExecStart=/usr/bin/bar --option1 --option2     # More than one ExecStart can be used if required

    [Install]
    WantedBy=timer-daily.target

Then, start and enable the service.

### Enable and start the timers

    # systemctl enable timer-{hourly,daily,weekly,monthly,yearly}.timer
    # systemctl start timer-{hourly,daily,weekly,monthly,yearly}.timer

## Starting events according to the calendar

If you wish to start a service according to a calendar event and not a monotonic interval (i.e. you wish to replace the functionality of crontab), you will need to create a new timer and link your service file to that. An example would be:

    /etc/systemd/system/foo.timer

    [Unit]
    Description=foo timer

    [Timer]
    # To add a time of your choosing here, please refer to systemd.time manual page for the correct format
    OnCalendar=Mon-Thu *-9-28 *:30:00
    Persistent=true
    Unit=foo.service

    [Install]
    WantedBy=basic.target

The service file may be created the same way as the events for monotonic clocks. However, take care to put them in the `/etc/systemd/system/` folder.

## Custom/example service files

Note: These example scripts assume that you have created the hourly, daily and weekly timers as described above.

### Reflector

This service file may be used to update pacman's mirrorlist daily using the reflector script.

    /etc/systemd/system/timer-daily.target.wants/reflector.service

    [Unit]
    Description=Update the mirrorlist

    [Service]
    Nice=19
    IOSchedulingClass=2
    IOSchedulingPriority=7
    Type=oneshot
    ExecStart=/usr/bin/reflector --protocol http --latest 30 --number 20 --sort rate --save /etc/pacman.d/mirrorlist

Note: Check out the discussion for connectivity issues as reflector will fail and potentially stop your timer.
Note: Reflector's options should be tweaked according to users' criteria. Use case examples may be found in this forum post by Moderator/TU Xyne.

### The modprobed_db service

This service is of great use to people who compile their own kernels because it reduces compilation time by a significant amount. Refer to the Modprobed_db page for further details.

    /etc/systemd/system/modprobed_db.service

    [Unit]
    Description=Run modprobed_db
    Wants=timer-daily.target

    [Service]
    Type=oneshot
    RemainAfterExit=yes
    User=enter user here
    Nice=19
    IOSchedulingClass=2
    IOSchedulingPriority=7
    ExecStart=/usr/bin/modprobed_db store

    [Install]
    WantedBy=timer-daily.target

Then, start and enable the service

### Hosts-update service

Package hosts-update uses mvps blocklist to update `/etc/hosts`.

    /etc/systemd/system/timer-daily.target.wants/hosts-update.service

    [Unit]
    Description=Update hosts file
    After=network.target

    [Service]
    Nice=19
    IOSchedulingClass=2
    IOSchedulingPriority=7
    ExecStart=/usr/bin/hosts-update

    [Install]
    WantedBy=timer-daily.target

## See also

- https://fedoraproject.org/wiki/Features/SystemdCalendarTimers - systemd calendar timers on the Fedora Project wiki

Categories:

- Daemons and system services
- Boot process