These timers, like cron jobs, can, at a given time, trigger various actions on the system. For example - running shell scripts or programs. Timers can work, for example, once a day, and only on Mondays. Another example is a timer that fires every 15 minutes during business hours (from 8 am to 6 pm). But systemd timers can do something that cron jobs can't. For example, a timer can call a script or program a specified time after an event. Such an event can be the system boot or systemd startup, the completion of a previous task, or even the termination of a service that was previously called by a timer.
Timers used for system maintenance
When Fedora or another systemd-based Linux distribution is installed on a computer, several timers are created as part of the system's maintenance routines. These procedures are automatically performed on any Linux system. The corresponding timers trigger various service tasks, such as updating system databases, clearing temporary directories, rotating log files, and so on.
As an example, I will give here information about the timers that are available on the virtual machine that I used for experiments. Here, to get a list of all timers, I used the command
systemctl status *timer
... The asterisk wildcard plays the same role here as it does in other similar commands. Namely, it tells the system that we are interested in all the timers (timer units, they are also called "timer unit files" or "timer units") of systemd:
[root@testvm1 ~]# systemctl status *timer
β mlocate-updatedb.timer - Updates mlocate database every day
Loaded: loaded (/usr/lib/systemd/system/mlocate-updatedb.timer; enabled; vendor preset: enabled)
Active: active (waiting) since Tue 2020-06-02 08:02:33 EDT; 2 days ago
Trigger: Fri 2020-06-05 00:00:00 EDT; 15h left
Triggers: β mlocate-updatedb.service
Jun 02 08:02:33 testvm1.both.org systemd[1]: Started Updates mlocate database every day.
β logrotate.timer - Daily rotation of log files
Loaded: loaded (/usr/lib/systemd/system/logrotate.timer; enabled; vendor preset: enabled)
Active: active (waiting) since Tue 2020-06-02 08:02:33 EDT; 2 days ago
Trigger: Fri 2020-06-05 00:00:00 EDT; 15h left
Triggers: β logrotate.service
Docs: man:logrotate(8)
man:logrotate.conf(5)
Jun 02 08:02:33 testvm1.both.org systemd[1]: Started Daily rotation of log files.
β sysstat-summary.timer - Generate summary of yesterday's process accounting
Loaded: loaded (/usr/lib/systemd/system/sysstat-summary.timer; enabled; vendor preset: enabled)
Active: active (waiting) since Tue 2020-06-02 08:02:33 EDT; 2 days ago
Trigger: Fri 2020-06-05 00:07:00 EDT; 15h left
Triggers: β sysstat-summary.service
Jun 02 08:02:33 testvm1.both.org systemd[1]: Started Generate summary of yesterday's process accounting.
β fstrim.timer - Discard unused blocks once a week
Loaded: loaded (/usr/lib/systemd/system/fstrim.timer; enabled; vendor preset: enabled)
Active: active (waiting) since Tue 2020-06-02 08:02:33 EDT; 2 days ago
Trigger: Mon 2020-06-08 00:00:00 EDT; 3 days left
Triggers: β fstrim.service
Docs: man:fstrim
Jun 02 08:02:33 testvm1.both.org systemd[1]: Started Discard unused blocks once a week.
β sysstat-collect.timer - Run system activity accounting tool every 10 minutes
Loaded: loaded (/usr/lib/systemd/system/sysstat-collect.timer; enabled; vendor preset: enabled)
Active: active (waiting) since Tue 2020-06-02 08:02:33 EDT; 2 days ago
Trigger: Thu 2020-06-04 08:50:00 EDT; 41s left
Triggers: β sysstat-collect.service
Jun 02 08:02:33 testvm1.both.org systemd[1]: Started Run system activity accounting tool every 10 minutes.
β dnf-makecache.timer - dnf makecache --timer
Loaded: loaded (/usr/lib/systemd/system/dnf-makecache.timer; enabled; vendor preset: enabled)
Active: active (waiting) since Tue 2020-06-02 08:02:33 EDT; 2 days ago
Trigger: Thu 2020-06-04 08:51:00 EDT; 1min 41s left
Triggers: β dnf-makecache.service
Jun 02 08:02:33 testvm1.both.org systemd[1]: Started dnf makecache βtimer.
β systemd-tmpfiles-clean.timer - Daily Cleanup of Temporary Directories
Loaded: loaded (/usr/lib/systemd/system/systemd-tmpfiles-clean.timer; static; vendor preset: disabled)
Active: active (waiting) since Tue 2020-06-02 08:02:33 EDT; 2 days ago
Trigger: Fri 2020-06-05 08:19:00 EDT; 23h left
Triggers: β systemd-tmpfiles-clean.service
Docs: man:tmpfiles.d(5)
man:systemd-tmpfiles(8)
Jun 02 08:02:33 testvm1.both.org systemd[1]: Started Daily Cleanup of Temporary Directories.
Each timer is associated with at least six lines containing information about it:
- The first line contains the name of the timer file and a short description of the purpose of the timer's existence.
- The second line displays information about the state of the timer. Namely, it reports whether it is loaded, gives the full path to the timer file, shows the vendor preset state (disabled or enabled).
- The third line shows information about the activity of the timer, which includes information about when the timer was activated.
- The fourth line contains the date and time of the next start of the timer and the approximate time remaining until it starts.
- The fifth line gives the name of the service or event called by the timer.
- Some (but not all) systemd timer unit files contain pointers to documentation. Such pointers are, in my example, in the descriptions of three timers.
- The last line in the timer description is the log entry that is associated with the most recent instance of the service called by the timer.
If you try to execute a command on your computer
systemctl status *timer
, the set of timers presented to it may well differ from mine.
Timer creation
Although we could figure out the specifics of how timers work by analyzing any existing timers, I suggest creating your own service unit file (service configuration file, service unit ) and a timer file with which the corresponding service will be called. We are here, in order not to complicate the story, give a rather trivial example. But after we deal with it, it will be easier for you to understand the work of other timers.
First, let's create a simple service configuration file that will run something as simple as a command
free
. For example, this may be needed if we need to regularly monitor the amount of free memory. Let's create a unit file named myMonitor.service
in the folder /etc/systemd/system
. It doesn't have to be executable.
# This service unit is for testing timer units
# By David Both
# Licensed under GPL V2
#
[Unit]
Description=Logs system statistics to the systemd journal
Wants=myMonitor.timer
[Service]
Type=oneshot
ExecStart=/usr/bin/free
[Install]
WantedBy=multi-user.target
This file is probably the simplest service configuration file. Now let's check its status and test it to make sure that it works as expected.
[root@testvm1 system]# systemctl status myMonitor.service
β myMonitor.service - Logs system statistics to the systemd journal
Loaded: loaded (/etc/systemd/system/myMonitor.service; disabled; vendor preset: disabled)
Active: inactive (dead)
[root@testvm1 system]# systemctl start myMonitor.service
[root@testvm1 system]#
Why isn't anything being output to the console? This is because, by default, standard output (
stdout
) from programs started by systemd using service unit files is redirected to the systemd log. Due to this, at least as long as the corresponding records exist, these records can be analyzed. Let's take a look at the log and look for entries related to our service and the day we tested. The corresponding command will look like this : journalctl -S today -u myMonitor.service
. The key -S
is an abbreviated version --since
. It allows you to specify the time period for which the utilityjournalctl
looking for records. The point is not that we are not interested in earlier results. In our case, such results simply will not be. This key is used to reduce the time the utility needs to search for data. If the computer has been working for a long time, a lot of entries can accumulate in the log.
[root@testvm1 system]# journalctl -S today -u myMonitor.service
-- Logs begin at Mon 2020-06-08 07:47:20 EDT, end at Thu 2020-06-11 09:40:47 EDT. --
Jun 11 09:12:09 testvm1.both.org systemd[1]: Starting Logs system statistics to the systemd journal...
Jun 11 09:12:09 testvm1.both.org free[377966]: total used free shared buff/cache available
Jun 11 09:12:09 testvm1.both.org free[377966]: Mem: 12635740 522868 11032860 8016 1080012 11821508
Jun 11 09:12:09 testvm1.both.org free[377966]: Swap: 8388604 0 8388604
Jun 11 09:12:09 testvm1.both.org systemd[1]: myMonitor.service: Succeeded.
[root@testvm1 system]#
A task that is launched using a service configuration file can be represented as a single program, a sequence of programs, or a script written in any scripting language. Let's add
myMonitor.service
another task to the unit file , including the [Service]
following at the end of the section :
ExecStart=/usr/bin/lsblk
Let's start the service again and check the log. There should be something in there that resembles what is shown below. Namely, the log should contain the data output by both commands:
Jun 11 15:42:18 testvm1.both.org systemd[1]: Starting Logs system statistics to the systemd journal...
Jun 11 15:42:18 testvm1.both.org free[379961]: total used free shared buff/cache available
Jun 11 15:42:18 testvm1.both.org free[379961]: Mem: 12635740 531788 11019540 8024 1084412 11812272
Jun 11 15:42:18 testvm1.both.org free[379961]: Swap: 8388604 0 8388604
Jun 11 15:42:18 testvm1.both.org lsblk[379962]: NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
Jun 11 15:42:18 testvm1.both.org lsblk[379962]: sda 8:0 0 120G 0 disk
Jun 11 15:42:18 testvm1.both.org lsblk[379962]: ββsda1 8:1 0 4G 0 part /boot
Jun 11 15:42:18 testvm1.both.org lsblk[379962]: ββsda2 8:2 0 116G 0 part
Jun 11 15:42:18 testvm1.both.org lsblk[379962]: ββVG01-root 253:0 0 5G 0 lvm /
Jun 11 15:42:18 testvm1.both.org lsblk[379962]: ββVG01-swap 253:1 0 8G 0 lvm [SWAP]
Jun 11 15:42:18 testvm1.both.org lsblk[379962]: ββVG01-usr 253:2 0 30G 0 lvm /usr
Jun 11 15:42:18 testvm1.both.org lsblk[379962]: ββVG01-tmp 253:3 0 10G 0 lvm /tmp
Jun 11 15:42:18 testvm1.both.org lsblk[379962]: ββVG01-var 253:4 0 20G 0 lvm /var
Jun 11 15:42:18 testvm1.both.org lsblk[379962]: ββVG01-home 253:5 0 10G 0 lvm /home
Jun 11 15:42:18 testvm1.both.org lsblk[379962]: sr0 11:0 1 1024M 0 rom
Jun 11 15:42:18 testvm1.both.org systemd[1]: myMonitor.service: Succeeded.
Jun 11 15:42:18 testvm1.both.org systemd[1]: Finished Logs system statistics to the systemd journal.
Now, after we are sure that everything is working correctly, we will create, in the folder
/etc/systemd/system
, a timer unit file, giving it a name myMonitor.timer
. Add the following to the file:
# This timer unit is for testing
# By David Both
# Licensed under GPL V2
#
[Unit]
Description=Logs some system statistics to the systemd journal
Requires=myMonitor.service
[Timer]
Unit=myMonitor.service
OnCalendar=*-*-* *:*:00
[Install]
WantedBy=timers.target
The timestamp
OnCalendar
in this file,, *-*-* *:*:00
should cause the timer to call the unit myMonitor.service
every minute. OnCalendar
We'll talk more about it below.
In the meantime, we can take a look at the log entries related to starting the timer service. We can also turn on the timer watch mode. However, monitoring the service will allow you to see the results in near real time. To do this, you need to run
journalctl
with the key -f
( follow
):
[root@testvm1 system]# journalctl -S today -f -u myMonitor.service
-- Logs begin at Mon 2020-06-08 07:47:20 EDT. --
Start the timer, but do not include it in autostart at system boot.
[root@testvm1 ~]# systemctl start myMonitor.timer
[root@testvm1 ~]#
Watch what happens for a while.
One of the results appears immediately. And the next ones will be displayed at intervals of about one minute. Watch the magazine for a few minutes.
[root@testvm1 system]# journalctl -S today -f -u myMonitor.service
-- Logs begin at Mon 2020-06-08 07:47:20 EDT. --
Jun 13 08:39:18 testvm1.both.org systemd[1]: Starting Logs system statistics to the systemd journal...
Jun 13 08:39:18 testvm1.both.org systemd[1]: myMonitor.service: Succeeded.
Jun 13 08:39:19 testvm1.both.org free[630566]: total used free shared buff/cache available
Jun 13 08:39:19 testvm1.both.org free[630566]: Mem: 12635740 556604 10965516 8036 1113620 11785628
Jun 13 08:39:19 testvm1.both.org free[630566]: Swap: 8388604 0 8388604
Jun 13 08:39:18 testvm1.both.org systemd[1]: Finished Logs system statistics to the systemd journal.
Jun 13 08:39:19 testvm1.both.org lsblk[630567]: NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
Jun 13 08:39:19 testvm1.both.org lsblk[630567]: sda 8:0 0 120G 0 disk
Jun 13 08:39:19 testvm1.both.org lsblk[630567]: ββsda1 8:1 0 4G 0 part /boot
Jun 13 08:39:19 testvm1.both.org lsblk[630567]: ββsda2 8:2 0 116G 0 part
Jun 13 08:39:19 testvm1.both.org lsblk[630567]: ββVG01-root 253:0 0 5G 0 lvm /
Jun 13 08:39:19 testvm1.both.org lsblk[630567]: ββVG01-swap 253:1 0 8G 0 lvm [SWAP]
Jun 13 08:39:19 testvm1.both.org lsblk[630567]: ββVG01-usr 253:2 0 30G 0 lvm /usr
Jun 13 08:39:19 testvm1.both.org lsblk[630567]: ββVG01-tmp 253:3 0 10G 0 lvm /tmp
Jun 13 08:39:19 testvm1.both.org lsblk[630567]: ββVG01-var 253:4 0 20G 0 lvm /var
Jun 13 08:39:19 testvm1.both.org lsblk[630567]: ββVG01-home 253:5 0 10G 0 lvm /home
Jun 13 08:39:19 testvm1.both.org lsblk[630567]: sr0 11:0 1 1024M 0 rom
Jun 13 08:40:46 testvm1.both.org systemd[1]: Starting Logs system statistics to the systemd journal...
Jun 13 08:40:46 testvm1.both.org free[630572]: total used free shared buff/cache available
Jun 13 08:40:46 testvm1.both.org free[630572]: Mem: 12635740 555228 10966836 8036 1113676 11786996
Jun 13 08:40:46 testvm1.both.org free[630572]: Swap: 8388604 0 8388604
Jun 13 08:40:46 testvm1.both.org lsblk[630574]: NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
Jun 13 08:40:46 testvm1.both.org lsblk[630574]: sda 8:0 0 120G 0 disk
Jun 13 08:40:46 testvm1.both.org lsblk[630574]: ββsda1 8:1 0 4G 0 part /boot
Jun 13 08:40:46 testvm1.both.org lsblk[630574]: ββsda2 8:2 0 116G 0 part
Jun 13 08:40:46 testvm1.both.org lsblk[630574]: ββVG01-root 253:0 0 5G 0 lvm /
Jun 13 08:40:46 testvm1.both.org lsblk[630574]: ββVG01-swap 253:1 0 8G 0 lvm [SWAP]
Jun 13 08:40:46 testvm1.both.org lsblk[630574]: ββVG01-usr 253:2 0 30G 0 lvm /usr
Jun 13 08:40:46 testvm1.both.org lsblk[630574]: ββVG01-tmp 253:3 0 10G 0 lvm /tmp
Jun 13 08:40:46 testvm1.both.org lsblk[630574]: ββVG01-var 253:4 0 20G 0 lvm /var
Jun 13 08:40:46 testvm1.both.org lsblk[630574]: ββVG01-home 253:5 0 10G 0 lvm /home
Jun 13 08:40:46 testvm1.both.org lsblk[630574]: sr0 11:0 1 1024M 0 rom
Jun 13 08:40:46 testvm1.both.org systemd[1]: myMonitor.service: Succeeded.
Jun 13 08:40:46 testvm1.both.org systemd[1]: Finished Logs system statistics to the systemd journal.
Jun 13 08:41:46 testvm1.both.org systemd[1]: Starting Logs system statistics to the systemd journal...
Jun 13 08:41:46 testvm1.both.org free[630580]: total used free shared buff/cache available
Jun 13 08:41:46 testvm1.both.org free[630580]: Mem: 12635740 553488 10968564 8036 1113688 11788744
Jun 13 08:41:46 testvm1.both.org free[630580]: Swap: 8388604 0 8388604
Jun 13 08:41:47 testvm1.both.org lsblk[630581]: NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
Jun 13 08:41:47 testvm1.both.org lsblk[630581]: sda 8:0 0 120G 0 disk
Jun 13 08:41:47 testvm1.both.org lsblk[630581]: ββsda1 8:1 0 4G 0 part /boot
Jun 13 08:41:47 testvm1.both.org lsblk[630581]: ββsda2 8:2 0 116G 0 part
Jun 13 08:41:47 testvm1.both.org lsblk[630581]: ββVG01-root 253:0 0 5G 0 lvm /
Jun 13 08:41:47 testvm1.both.org lsblk[630581]: ββVG01-swap 253:1 0 8G 0 lvm [SWAP]
Jun 13 08:41:47 testvm1.both.org lsblk[630581]: ββVG01-usr 253:2 0 30G 0 lvm /usr
Jun 13 08:41:47 testvm1.both.org lsblk[630581]: ββVG01-tmp 253:3 0 10G 0 lvm /tmp
Jun 13 08:41:47 testvm1.both.org lsblk[630581]: ββVG01-var 253:4 0 20G 0 lvm /var
Jun 13 08:41:47 testvm1.both.org lsblk[630581]: ββVG01-home 253:5 0 10G 0 lvm /home
Jun 13 08:41:47 testvm1.both.org lsblk[630581]: sr0 11:0 1 1024M 0 rom
Jun 13 08:41:47 testvm1.both.org systemd[1]: myMonitor.service: Succeeded.
Jun 13 08:41:47 testvm1.both.org systemd[1]: Finished Logs system statistics to the systemd journal.
Be sure to check both the timer status and the service status.
Did you manage to notice here what I noticed? You may have noticed at least two things as you read the magazine.
Firstly - the fact that you do not need to do something special for logging that
ExecStart
of myMonitor.service
writing in stdout
. This feature is part of the standard systemd startup functions. But this means that you will probably need to be careful when running scripts from service configuration files, noting how much data they write to stdout
.
Secondly, you may have noticed that the timer does not start exactly at
:00
seconds of every minute, and not even exactly one minute after the last run. This is one of the features of such timers, if it is necessary (or if it hurts the feelings of the system administrator), this behavior of the timers can be changed by making them more accurate.
The reason that the timer does not start in
:00
seconds of every minute is because the system thus tends to prevent multiple services from starting simultaneously. For example, when setting up the time indicator, OnCalendar
you can use values ββsuch as Weekly
, Daily
and others. These shorthand ways of naming points in time are configured so that the timers in which they are used start at00:00:00
the corresponding day. When multiple timers are configured this way, the chances are high that they will all fire at the same time.
This is why systemd timers are deliberately designed so that they do not start at exactly the specified time, but with some random deviation from it. This deviation cannot be called completely accidental. Timers start somewhere in a time window that starts at the specified moment and ends at one minute from the original. This time, in accordance with the documentation for
systemd.timer
, is maintained in a stable state, taking into account all other timers declared in the system. In the above log fragment, you can see that the timer is triggered immediately after it starts, and then - approximately 46 or 47 seconds after the start of each next minute.
Most often, such a probabilistic approach to determining the exact timing of the timers suits everyone. When scheduling tasks such as making a backup copy of something while such tasks are performed outside of business hours, this does not cause any problems. The system administrator, setting up cron jobs, can specify clearly defined times to start them, something like
01:05:00
trying to ensure that these jobs do not conflict with others. There is a wide range of ways of specifying the time that allow this. Random changes in the start time of a task that do not exceed a minute usually do not play a special role.
But for some tasks, the exact timing of the timer is extremely important. In such cases, when setting the timers, you can specify a more accurate time of their operation (up to the accuracy, measured in microseconds). This is done by adding to the timer description file, in the section
Timer
, a construction that resembles the following:
AccuracySec=1us
You can use special keywords to specify the desired precision of the timer. These keywords can also be used when setting up recurring and one-time events. The system understands the following keywords:
- Microsecond:
usec
,us
,Β΅s
. - Millisecond:
msec
,ms
. - Second:
seconds
,second
,sec
,s
. - Minute:
minutes
,minute
,min
,m
. - Hour:
hours
,hour
,hr
,h
. - Day:
days
,day
,d
. - Week:
weeks
,week
,w
. - Month:
months
,month
,M
(the month is defined as 30.44 days). - Year:
years
,year
,y
(the year is defined as 365.25 days).
All standard timers that are available in
/usr/lib/systemd/system
are configured using much longer ranges that set the accuracy of their triggering, since in the case of these timers, their triggering at a strictly specified time is not particularly important. Take a look at the specs of some of the system generated timers:
[root@testvm1 system]# grep Accur /usr/lib/systemd/system/*timer
/usr/lib/systemd/system/fstrim.timer:AccuracySec=1h
/usr/lib/systemd/system/logrotate.timer:AccuracySec=1h
/usr/lib/systemd/system/logwatch.timer:AccuracySec=12h
/usr/lib/systemd/system/mlocate-updatedb.timer:AccuracySec=24h
/usr/lib/systemd/system/raid-check.timer:AccuracySec=24h
/usr/lib/systemd/system/unbound-anchor.timer:AccuracySec=24h
[root@testvm1 system]#
To get a better understanding of the internal structure of the timer files from the directory
/usr/lib/systemd/system
, you can view their contents.
You do not need to configure our learning timer to activate when your system boots. However, if you want, you can use the following command for this:
[root@testvm1 system]# systemctl enable myMonitor.timer
The timer files that you will create do not need to be executable. In addition, service configuration files do not need to be configured to be activated at boot, as they are called by timers. If necessary, the service can also be called manually from the command line. Try this and look in the systemd log.
To learn more about the accuracy of timers, how to specify the time of event triggering, and how to trigger events, see the documentation for
systemd.timer
and systemd.time
.
Timer types
Systemd timers have other features that cron jobs do not have, one-off or repetitive, that are invoked only with real-time and real-time dates. Systemd timers can be configured to be called based on changes in the state of other systemd units. For example, the timer can be configured so that it would be triggered after a specified time after the system boots, after the user logs into it, or after a specified time after activating a certain service. These timers are called monotonic. These timers are reset after every system reboot.
The following table shows a list of monotonic timers with a brief description of each of them. There is also a description of the timer.
OnCalendar
, which is not monotonous and is used in cases where you need to organize a one-time or repeated launch of something in the future. This table is based on documentation systemd.timer
.
Timer | Monotone | Description |
|
X | The timer operation time is set relative to the moment of the timer activation. |
|
X | The timer is set relative to the moment the system boots. |
|
X | . OnBootSec= , . , , , , , . |
|
X | , , , . |
|
X | , , , . |
|
. systemd.time(7) . OnActiveSec= . β systemd, , cron. |
When setting monotonic timers, the same keywords can be used as described above when talking about
AccuracySec
. But it should be noted that systemd converts the corresponding time intervals to seconds. For example, you might want to set a timer that fires once, five days after the system boots. It may look like a description like this: OnBootSec=5d
. If the computer was booted 2020-06-15
at 09:45:27
, the timer will start 2020-06-20
at 09:45:27
(or within 1 minute after this point in time).
Description of calendar events
Applying calendar events is a key part of describing timers that are called at regular intervals. Let us examine some of the features of such events used when setting the time indicator
OnCalendar
.
Systemd and its corresponding timers use a different time and date format than crontab. This format is more flexible than the one used in crontab. It allows you to specify the date and time in a simplified way, in command style
at
. For those familiar with it at
, it should be easy to understand the systemd timer settings.
When used
OnCalendar=
to configure timers, the following basic format is used for specifying the date and time:
DOW YYYY-MM-DD HH:MM:SS
DOW
(Day Of Week), this is an optional part of the above construct. In other fields, you can use the asterisk ( *
) symbol to represent any value that may appear in the position it occupies. All forms of indication of date and time are converted to normalized form. If no time is specified, it is assumed to be 00:00:00
. If the date is not specified, but the time is specified, then the timer will work either on the day it starts (relatively speaking, "today"), or the next day ("tomorrow"). It depends on the current time. Months and days of the week can be named by names. You can use comma-separated lists of values ββhere. Ranges of values ββcan be separated by three dots ( β¦
) between the start and end value of the range.
When specifying dates, we have a couple of interesting options at our disposal. Thus, a tilde (~) can be used to indicate the last day of a month, or to indicate a date a given number of days before the last day of the month. The forward slash (/) can be used as a modifier to indicate the day of the week.
The following table shows some typical examples of timing used in an expression
OnCalendar
.
Example of presenting a calendar event DOW YYYY-MM-DD HH:MM:SS
|
Description |
|
Every day of every month of every year, 15 minutes 30 seconds after midnight. |
|
Every Monday at 00:00:00 . |
|
The same as Weekly . |
|
The same as Weekly . |
|
Every Wednesday 2020 at 00:00:00 . |
|
Every weekday in 2021 at 00:00:00 . |
|
June 1 and 15, July and August 2022 01:15:00 after midnight. |
|
, , , 3 . |
|
, 4 , . |
|
3 , , β , . . , ~ . |
|
, β . . , (- ). |
,
Systemd has a great tool for checking and examining calendar event specifications. This is a team
systemd-analyze calendar
that parses descriptions of calendar events and presents them in a normalized form. This command also provides other interesting information, such as the date and time of the next such event, and the approximate time remaining until that moment.
First, let's take a look at the specification, which contains only the date, does not contain information about the time (note that the times in the fields
Next elapse
and (in UTC)
are different, this difference depends on the local time zone):
[student@studentvm1 ~]$ systemd-analyze calendar 2030-06-17
Original form: 2030-06-17
Normalized form: 2030-06-17 00:00:00
Next elapse: Mon 2030-06-17 00:00:00 EDT
(in UTC): Mon 2030-06-17 04:00:00 UTC
From now: 10 years 0 months left
[root@testvm1 system]#
Now let's add time information to the description. In this example, date and time are analyzed separately, as entities that are not related to each other:
[root@testvm1 system]# systemd-analyze calendar 2030-06-17 15:21:16
Original form: 2030-06-17
Normalized form: 2030-06-17 00:00:00
Next elapse: Mon 2030-06-17 00:00:00 EDT
(in UTC): Mon 2030-06-17 04:00:00 UTC
From now: 10 years 0 months left
Original form: 15:21:16
Normalized form: *-*-* 15:21:16
Next elapse: Mon 2020-06-15 15:21:16 EDT
(in UTC): Mon 2020-06-15 19:21:16 UTC
From now: 3h 55min left
[root@testvm1 system]#
Now consider an example where date and time are considered together. To do this, they must be enclosed in quotes. But if you use such a construction in
OnCalendar
, do not forget to remove the quotes, otherwise you will run into errors:
[root@testvm1 system]# systemd-analyze calendar "2030-06-17 15:21:16"
Normalized form: 2030-06-17 15:21:16
Next elapse: Mon 2030-06-17 15:21:16 EDT
(in UTC): Mon 2030-06-17 19:21:16 UTC
From now: 10 years 0 months left
[root@testvm1 system]#
Now let's check something from the previous table. I especially like this description from her:
2022-6,7,8-1,15 01:15:00
Let's analyze it:
[root@testvm1 system]# systemd-analyze calendar "2022-6,7,8-1,15 01:15:00"
Original form: 2022-6,7,8-1,15 01:15:00
Normalized form: 2022-06,07,08-01,15 01:15:00
Next elapse: Wed 2022-06-01 01:15:00 EDT
(in UTC): Wed 2022-06-01 05:15:00 UTC
From now: 1 years 11 months left
[root@testvm1 system]#
Now let's take a look at the description
Mon *-05~3
, but this time we will ask the program for information about the next 5 times of the timer, which uses the following settings:
[root@testvm1 ~]# systemd-analyze calendar --iterations=5 "Mon *-05~3"
Original form: Mon *-05~3
Normalized form: Mon *-05~03 00:00:00
Next elapse: Mon 2023-05-29 00:00:00 EDT
(in UTC): Mon 2023-05-29 04:00:00 UTC
From now: 2 years 11 months left
Iter. #2: Mon 2028-05-29 00:00:00 EDT
(in UTC): Mon 2028-05-29 04:00:00 UTC
From now: 7 years 11 months left
Iter. #3: Mon 2034-05-29 00:00:00 EDT
(in UTC): Mon 2034-05-29 04:00:00 UTC
From now: 13 years 11 months left
Iter. #4: Mon 2045-05-29 00:00:00 EDT
(in UTC): Mon 2045-05-29 04:00:00 UTC
From now: 24 years 11 months left
Iter. #5: Mon 2051-05-29 00:00:00 EDT
(in UTC): Mon 2051-05-29 04:00:00 UTC
From now: 30 years 11 months left
[root@testvm1 ~]#
I believe we've covered enough use cases
systemd-analyze calendar
to get you started testing your own calendar event definitions. Keep in mind that the tool systemd-analyze
has other interesting features.
Additional materials
There are many publications on systemd on the internet, but they are mostly too short, very simplistic, or even buggy. This article provides some good sources of information on systemd. Below is a list of links to some more quality materials on this topic.
- A practical guide to systemd by the Fedora Project.
- A cheat sheet from the Fedora Project that maps the legacy SystemV and systemd commands.
- Details about systemd and why it was created.
- Material with information and advice, dedicated to systemd.
- (Lennart Poettering), systemd. , 2010 2011, . systemd .
- systemd.
- systemd.
Systemd timers can be used to accomplish the same tasks that cron jobs do. But systemd gives you more flexibility in terms of configuring calendar and monotonic timers.
Even though the service configuration files we create during our experiments are usually called using timers, you can call them at any time using a command like
systemctl start myMonitor.service
. One timer can start several tasks. This can be, for example, Bash scripts and Linux utilities. A service configuration file can be composed so that when it is called, multiple scripts are executed. You can also make the scripts run separately.
If we talk about the coexistence of systemd, cron and at, then I want to note that I have not yet seen any signs that cron or at would be deprecated. I hope they will continue to be supported, since at is at least much easier than systemd to use for scheduling one-off tasks.
What are you using? Systemd timers or cron jobs?