Systemd has provided timers for a while and it is worth taking a look at this feature as an alternative to cron. This article will show you how to use timers with systemd to run a task after the system has booted and on a recurring basis after that. This is not a comprehensive discussion of systemd, only an introduction to this one feature.
Cron vs anacron vs systemd: a quick review
Cron can schedule a task to be run at a granularity ranging from minutes to months or more. It is relatively simple to set up, requiring a single configuration file. Although the configuration line is somewhat esoteric. It can also be used by general users.
Cron, however, fails if your system happens to not be running when the appropriate execution time occurs.
Anacron, overcomes the “system not running” issue. It insures that the task will be executed when your system is again active. While it was intended to be used by administrators, some systems give general users access.
However, the anacron frequency of execution can be no less than daily.
Both cron and anacron have issues with consistency in execution context. Care must be taken that the environment in effect when the task runs is exactly that used when testing. The same shell, environment variables and paths must be provided. This means that testing and debugging can sometimes be difficult.
Systemd timers offer the best of both cron and anacron. Allows scheduling down to minute granularity. Assures that the task will be executed when the system is again running even if it was off during the expected execution time. Is available to all users. You can test and debug the execution in the environment it will run in.
However, the configuration is more involved, requiring at least two configuration files.
If your cron and anacron configuration is serving you well then there may not be a reason to change. But systemd is at least worth investigating since it may simplify any current cron /anacron work-arounds.
Systemd timer executed functions require, at a minimum, two files. These are the “timer unit” and the “service unit”. Actions consisting of more than a simple command, you will also need a “job” file or script to perform the necessary functions.
The timer unit file defines the schedule while the service unit file defines the task(s) performed. More details on the .timer unit is available in “man systemd.timer”. Details on the service unit are available in “man systemd.service”.
There are several locations where unit files exist (listed in the man page). Perhaps the easiest location for the general user, however, is “~/.config/systemd/user”. Note that “user” here, is the literal string “user”.
This demo is a simple example creating a user scheduled job rather than a system schedule job (which would run as root). It prints a message, date, and time to a file.
- Start by creating a shell script that will perform the task. Create this in your local “bin” directory, for example, in
To create the file:touch ~/bin/schedule-test.sh
Then add the following content to the file you just created.
#!/bin/sh echo "This is only a test: $(date)" >> "$HOME/schedule-test-output.txt"
Remember to make your shell script executable.
- Create the .service unit that will call the script above. Create the directory and file in:
[Unit] Description=A job to test the systemd scheduler [Service] Type=simple ExecStart=/home/<user>/bin/schedule-test.sh [Install] WantedBy=default.target
Note that <user> should be your @HOME address but the “user” in the path name for the unit file is literally the string “user”.
The ExecStart line should provide an absolute address with no variables. An exception to this is that for user units you may substitute “%h” for $HOME. In other words you can use:
This is only for user unit file use. It is not good for system units since “%h” will always return “/root” when run in the system environment. Other substitutions are found in “man systemd.unit” under the heading “SPECIFIERS”. As it is outside the scope of this article, that’s all we need to know about SPECIFIERS for now.
3. Create a .timer unit file which actually schedules the .service unit you just created. Create it in the same location as the .service file “~/.config/systemd/user/schedule-test.timer”. Note that the file names differ only in their extensions, that is ,”.service” versus “.timer”
[Unit] Description=Schedule a message every 1 minute RefuseManualStart=no # Allow manual starts RefuseManualStop=no # Allow manual stops [Timer] #Execute job if it missed a run due to machine being off Persistent=true #Run 120 seconds after boot for the first time OnBootSec=120 #Run every 1 minute thereafter OnUnitActiveSec=60 #File describing job to execute Unit=schedule-test.service [Install] WantedBy=timers.target
Note that the .timer file has used “OnUnitActiveSec” to specify the schedule. Much more flexible is the “OnCalendar” option. For example:
# run on the minute of every minute every hour of every day OnCalendar=*-*-* *:*:00 # run on the hour of every hour of every day OnCalendar=*-*-* *:00:00 # run every day OnCalendar=*-*-* 00:00:00 # run 11:12:13 of the first or fifth day of any month of the year # 2012, but only if that day is a Thursday or Friday OnCalendar=Thu,Fri 2012-*-1,5 11:12:13
More information on “OnCalendar” is available here.
4. All the pieces are in place but you should test to make certain everything works. First, enable the user service:
$ systemctl --user enable schedule-test.service
This should result in output similar to this:
Created symlink /home/<user>/.config/systemd/user/default.target.wants/schedule-test.service → /home/<user>/.config/systemd/user/schedule-test.service.
Now do a test run of the job:
$ systemctl --user start schedule-test.service
Check your output file ( $HOME/schedule-test-output.txt ) to insure that your script is
performing correctly. There should be a single entry since we have not started the timer yet. Debug as necessary. Don’t forget to enable the service again if you needed to change your .service file as opposed to the shell script it invokes.
5. Once the job works correctly, schedule it for real by enabling and starting the user timer for your service:
$ systemctl --user enable schedule-test.timer $ systemctl --user start schedule-test.timer
Note that you have already started and enabled the service in step 4, above, so it is only necessary to enable and start the timer for it.
The “enable” command will result in output similar to this:
Created symlink /home/<user>/.config/systemd/user/timers.target.wants/schedule-test.timer → /home/<user>/.config/systemd/user/schedule-test.timer.
and the “start” will simply return you to a CLI prompt.
You can check and monitor the service. The first command below is particularly useful if you receive an error from the service unit:
$ systemctl --user status schedule-test $ systemctl --user list-unit-files
Manually stop the service:
$ systemctl --user stop schedule-test.service
Permanently stop and disable the timer and the service, reload the daemon config and reset any failure notifications:
$ systemctl --user stop schedule-test.timer $ systemctl --user disable schedule-test.timer $ systemctl --user stop schedule-test.service $ systemctl --user disable schedule-test.service $ systemctl --user daemon-reload $ systemctl --user reset-failed
This article will jump-start you with systemd timers, however, there is much more to systemd than covered here. This article should provide you with a foundation on which to build. You can explore more about it starting in the Fedora Magazine systemd series .
References – Further reading:
- man systemd.timer
- man systemd.service
- Use systemd timers instead of cronjobs
- Understanding and administering systemd
- Also, https://opensource.com/ has a good systemd cheatsheet
Very nice article, but actually, I would prefer a graphical user interface or management platform for setting up timers, due to the amount of tasks one has to manage and the syntax you need to get used to.
I not dealing very often with the topic.
This sounds like a good inclusion for cockpit
Indeed, and it has been corrected. Thank you for letting me know.
Good article to get rid of
One can also ommit
file and rely on the implicit rule ”
controlls the start of
“, as recommended in the manage.
One thing of note; and something I’ve done for another Fedora install is using these timer services to automate Fedora updates. In fact, I feel there’s an article covering just that.
There seems to be a option available for displaying timers in Cockpit, but you can’t create a timer from that view under services —> timer. I’ve found a bug from 2017 for that issue.
Ok, I’m unsure if I’m missing a button hidden somewhere else…
If you change your Cockpit session to “Administrative access” then the “timer” category under “Services” will include a “Create timer” button at the top of the page. This does not exist for “Limited access” so I believe the processes will not run as a user, only as root.
I do not have extensive experience with Cockpit so perhaps someone else will be able to elaborate on this.
I have no root access for Cockpit right now, but will test that soon. Thanks a lot!
You wrote “OnCalender” but it should be “OnCalendar”.
Thank you. Corrections made. Cut’n’paste not necessarily your friend.
Note that you can actually also use a CLI command (”systemctl edit –force –full –user schedule-test.service”) to create that service (or timer units etc.) without having to manually create and remember that compliacted file path. 😉
That’s great to know. Thanks for adding that to the conversation.
I haven’t found the cheat sheet on the first click in the menu, so that would be the direct link: https://opensource.com/downloads/linux-systemd-cheat-sheet
Fantastic website, which I wasn’t aware for whatever reason.
I’ve found a guide for inter-process communication there. I was long searching for an appropriate guide in an suitable length. Perfect!
Thanks, Ralf. I’ve added that more direct link.
Hugo Leonardo R. D. Lopes
Good evening! I really liked the article. Very well explained. Congratulations. However, there is a caveat that I would like to make and that I have been hitting on this key since 2000. For users who have technical knowledge of Linux it is easy to do, but the community has not yet seen the reality of the world we live in, nor who the people are with no programming or technical knowledge, I would like to use the much talked about Linux. The hotdog guy, the lawyer, the mechanic, the school cook, my grandmother and grandfather, the geography teacher (history, chemistry, physical education, etc…), people who barely know how to send an email or attach something to it. At this point, Windows and Microsoft come out ahead since Windows 95 in terms of the end user’s vision, that is, people without knowledge. As far as the Linux crowd doesn’t make difficult things easy and port everything to an intuitive and easy-to-use graphical interface for anyone. Linux will always play a supporting role in the world of operating systems for simple people. “Wow! Do you use Linux? I wanted to understand how you use it! I prefer Windows, it’s easier!”
The most straight-forward answer is that there are always trade-offs. If Linux were to remove all of those confusing “options” so that there were just a few “easier” things to point and click on, then it would no longer be Linux.
It is very true that not everyone is the same in terms of their computer skills. You might find this 2016 study by the Organisation for Economic Co-operation and Development interesting:
The Distribution of Users’ Computer Skills: Worse Than You Think.
A one size fits all design really isn’t possible. Fedora Linux does try to accommodate the variety of users by offering a variety of “spins”. KDE, for example, tries to be more intuitive for people who are familiar with Windows. i3 is for people who do more work on the command line.
Thank you. I’m glad you liked the article.
The article, however, is written for someone that needs or wants to understand scheduling jobs with systemd. That task is something my grandmother, my mother, or the mechanic (don’t sell any of them short) has no need for in daily use on either OS.
Whether Windows is better than Linux really comes down to need and to a very large extent how trained and familiar you are with one or the other. From my experience teaching beginner Linux classes, I feel the opposite as you. I can teach someone who wants to learn how to use the GUI to be very proficient using either OS. There is typically no need for them to delve into the CLI unless they have the desire.
But Linux Desktop vs Windows is an old argument and this is probably not the place to try and solve it.
As a former windows user, I can confirm that the advanced scheduling features are somehow hidden from the user and I would say that most users never view (you will be overwhelmed by the amount of timers windows sets up by default), add or modify timers.
Some developers are working on a GUI here:
I haven’t tested the feature, but I would prefer it for that specific topic.
great idea this article. this knowledge is a real life need.
my experience: systemd scheduling is a fat monster that needs to be learned well.
And it has some advantages cron can never catch up with.
So yes, I use both.
Each where apropriate.
Please do never tell one of these mechanismns is always advantageous or better than the other – that would be a stupid lie distracting from there are proper areas of use for each of them.
Mallikarjungouda S Patil
It’s a very helpful article. Please post more like this on other Linux utilities. Thanks a lot!