Use Systemd as a Cron Replacement
Since systemd 197 timer units support calendar time events, which makes systemd a full cron replacement. Why one would replace the good old cron? Well, because systemd is good at executing stuff and monitor its state!
- with the help of journalctl you get last status and logging output, which is a great thing to debug failing jobs:
$ systemctl status reflector-update.service
reflector-update.service - "Update pacman's mirrorlist using reflector"
Loaded: loaded
(/etc/systemd/system/timer-weekly.target.wants/reflector-update.service)
Active: inactive (dead)
Jun 09 17:58:30 higgsboson reflector[30109]: rating http://www.gtlib.gatech.edu/pub/archlinux/
Jun 09 17:58:30 higgsboson reflector[30109]: rating rsync://rsync.gtlib.gatech.edu/archlinux/
Jun 09 17:58:30 higgsboson reflector[30109]: rating http://lug.mtu.edu/archlinux/
Jun 09 17:58:30 higgsboson reflector[30109]: Server Rate Time
...
- there are a lot of useful
systemd unit options
like
IOSchedulingPriority,NiceorJobTimeoutSec - it is possible to let depend units on other services, like mounting the nfs host before starting the mysql-backup.service or depending on the network.target.
So let’s get it started. The first thing you might want to do, is to replace the default scripts located in the runparts directories /etc/cron.{daily,hourly,monthly,weekly}.
On my distribution (archlinux) these are logrotate, man-db, shadow and updatedb: For convenience I created a structure like /etc/cron.*:
$ mkdir /etc/systemd/system/timer-{hourly,daily,weekly}.target.wants
and added the following timer.
$ cd /etc/systemd/system
$ wget https://blog.thalheim.io/downloads/timers.tar
$ tar -xvf timers.tar && rm timers.tar
[Unit]
Description=Hourly Timer
[Timer]
OnBootSec=5min
OnUnitActiveSec=1h
Unit=timer-hourly.target
[Install]
WantedBy=basic.target
[Unit]
Description=Hourly Timer Target
StopWhenUnneeded=yes
[Unit]
Description=Daily Timer
[Timer]
OnBootSec=10min
OnUnitActiveSec=1d
Unit=timer-daily.target
[Install]
WantedBy=basic.target
[Unit]
Description=Daily Timer Target
StopWhenUnneeded=yes
[Unit]
Description=Weekly Timer
[Timer]
OnBootSec=15min
OnUnitActiveSec=1w
Unit=timer-weekly.target
[Install]
WantedBy=basic.target
[Unit]
Description=Weekly Timer Target
StopWhenUnneeded=yes
… and enable them:
$ systemctl enable timer-hourly.timer
$ systemctl enable timer-daily.timer
$ systemctl enable timer-weekly.timer
These directories work like their cron equivalents, each service file located in such a directory will be executed at the given time.
Now move on to the service files. If you’re not running Arch, the paths might be different on your system.
$ cd /etc/systemd/system
$ wget https://blog.higgsboson.tk/downloads/services.tar
$ tar -xvf services.tar && rm services.tar
[Unit]
Description=Update man-db
[Service]
Nice=19
IOSchedulingClass=2
IOSchedulingPriority=7
ExecStart=/usr/bin/logrotate /etc/logrotate.conf
[Unit]
Description=Update man-db
[Service]
Nice=19
IOSchedulingClass=2
IOSchedulingPriority=7
ExecStart=/usr/bin/mandb --quiet
[Unit]
Description=Update mlocate database
[Service]
Nice=19
IOSchedulingClass=2
IOSchedulingPriority=7
ExecStart=/usr/bin/updatedb
[Unit]
Description=Verify integrity of password and group files
[Service]
Type=oneshot
ExecStart=/usr/sbin/pwck -r
ExecStart=/usr/sbin/grpck -r
At last but not least you can disable cron:
$ systemctl stop cronie && systemctl disable cronie
If you want to execute at a special calendar events for example “every first day in a month” use the “OnCalendar=” option in the timer file. example:
[Unit]
Description=Daily Timer
[Timer]
OnCalendar=*-*-1 0:0:O
Unit=send-bill.target
[Install]
WantedBy=basic.target
That’s all for the moment. Have a good time using the power of systemd!
Below some service files, I use:
[Unit]
Description="Update pacman's mirrorlist using reflector"
[Service]
Nice=19
IOSchedulingClass=2
IOSchedulingPriority=7
Type=oneshot
ExecStart=/usr/bin/reflector --verbose -l 5 --sort rate --save /etc/pacman.d/mirrorlist
[Unit]
Description=Run pkgstats
[Service]
User=nobody
ExecStart=/usr/bin/pkgstats
See this link for details about my shell-based pacman notifier
[Unit]
Description=Update pacman's package cache
[Service]
Nice=19
Type=oneshot
IOSchedulingClass=2
IOSchedulingPriority=7
Environment=CHECKUPDATE_DB=/var/lib/pacman/checkupdate
ExecStartPre=/bin/sh -c "/usr/bin/checkupdates > /var/log/pacman-updates.log"
ExecStart=/usr/bin/pacman --sync --upgrades --downloadonly --noconfirm --dbpath=/var/lib/pacman/checkupdate
Archived comments
Imported from Disqus, which this blog used before switching to giscus.
Profpatsch
What about cronjobs I want to execute in my useraccount?
Like automatic home folder backups every 3 hours?
Mic92
You have basicly 2 options: 1. create a custom timer in the context of
systemd/user (https://wiki.archlinux.org/.... 2. set
the User variable in the service file.
Buddlespit
This backs up my home to my home on the server:
[Unit]
Description=Backup ~/
Wants=timer-weekly.timer
[Service]
User=pat
Nice=19
IOSchedulingClass=2
IOSchedulingPriority=7
ExecStart=/usr/bin/rsync --delete -azvv -e ssh /home/pat/ pat@192.168.1.13:/home/pat/backup
[Install]
WantedBy=timer-weekly.target
Ken
I have the hourly daily weekly systemd cron replacement running but with one problem.
If I set up an hourly service "test.service" and enable it with:
"systemctl enable test.service"
a link to "test.service" is created in "timer-hourly.target.wants" as it should be.
I then remove it with:
"systemctl disable test.service"
the "timer-hourly.target.wants" directory is removed rather than just the link.
(if there are other links in "timer-hourly.target.wants" the directory survives)
What am I doing wrong ?
systemd 215
Mic92
Sound good to me, what behaviour did you expect?
Ken
Didn't expect the wants directory to disappear but now I realise the wants directories are created and deleted as required. Thanks for your comment.
ferrvittorio
Hi. What about if I tried to setup a daily shutdown at 2200. I am landing here from suse cron and I am not yet familiar.
Might the following suffice?
daily-shutdown.timer
[Unit]
Description="daily shutdown"
OnCalendar=*-*-* 22:0:0
Unit=daily-shutdown.timer
[Service]
Nice=19
IOSchedulingClass=2
IOSchedulingPriority=7
Type=oneshot
ExecStart=/path/to/shutdown
Mic92
the timer spec is correct should work, but you have to put service section in a separate file (if the name is the same except the suffix it will be pulled in by your timer)
daily-shutdown.timer
[Unit]
Description="daily shutdown"
[Timer]
OnCalendar=22:00
[Install]
WantedBy=multi-user.target
daily-shutdown.service
[Service]
Nice=19
IOSchedulingClass=2
IOSchedulingPriority=7
Type=oneshot
ExecStart=/path/to/shutdown
Enable it and start it with:
$ systemctl enable daily-shutdown.timer
$ systemctl start daily-shutdown.timer
To verify if it works use the subcommand:
$ systemctl list-timers
This will list, when the timer is scheduled.
ferrvittorio
Hi! Unit did shutdown, but .. something went really wrong!
LXDE refused to let me log back in, even as root. Login attempt as user jumped me at lxde screen, root loogin forced box to shut down!
For now I removed offending timer/service
What is your opinion
Edit: not LXDE, but LIGHTDM