6

I've noticed some significant variation in approach in some systemd documentation and how-to documents concerning how to configure one or more services to use the same timer.

As far as I have been able to piece together (though I may be wrong) this would describe what the WantedBy and Unit parameters in a Service and Timer file need to be set to (not using actual code examples here - in order to lessen post length) for a single service and conversely a multiple service configuration using a single timer:

Timer for a single service

My.Service1 'WantedBy' Param: N/A (1)
My.Timer 'Unit' Param: My.Service1 (2)
My.Timer 'WantedBy' Param: MultiUser/Basic.Target (3) 

(1) The service file does not need an [Install] section with a WantedBy parameter.

(2) In the timer's [Timer] section the Unit parameter should point to the My.Service1 service file.

(3) The timer file has a WantedBy parameter that points to some special system target that will be used to start it.

Timer for multiple services

My.Service1 'WantedBy' Param: Timer.Target (1)
My.Service2 'WantedBy' Param: Timer.Target (1)
My.Service3 'WantedBy' Param: Timer.Target (1)
Timer 'Unit' Param: Timer.Target (2)
Timer 'WantedBy' Param: ???

(1) The services need to all connect to the same defined target using the WantedBy parameter.

(2) The [Timer] Unit parameter should point to the target also.

For an example of the latter configuration see this how-to. I will count that as Example 1. However I have found other how-to examples that deviate from this (see below).

Example 2 and Example 3 say it should be configured like this:

My.Service1 WantedBy: Timer.Target
My.Service2 WantedBy: Timer.Target
My.Service3 WantedBy: Timer.Target
Timer 'Unit' Param: My.Service1 (1)
Timer 'WantedBy' Param: MultiUser/Basic.Target

(1) This has to be an oversight in the documentation because if you leave the unit pointing to only one of your multiple services the other services cannot use the timer. Possibly this was due to the "see above" approach utilized there to refer the reader back to the single service configuration without actually mentioning (importantly) what needed to change.

Then with Example 4 its configuration looks like it will actually work, but it goes about connecting the services with the target in a different way by creating the service files directly under the /etc/systemd/system/Timer.Target.wants/ subdirectory and excludes any WantedBy params in the service files. Thus:

My.Service1 'WantedBy' Param: N/A
My.Service2 'WantedBy' Param: N/A
My.Service3 'WantedBy' Param: N/A
Timer 'Unit' Param: Timer.Target
Timer 'WantedBy' Param: MultiUser/Basic.Target

A hybrid approach between Examples 1 and 4 that I've seen is to create the service files in the /etc/systemd/system/ directory (the default location) and to create a symbolic link to those service files under the /etc/systemd/system/Timer.Target.wants file and exclude a WantedBy param in the service file (which is functionally equivalent to Example 4), while another configuration uses the symbolic link method but in addition includes the WantedBy param in the service file (which seems redundant and unnecessary).

My question would be this though for the Example 4 & hybrid approaches: Why should putting anything under a *.wants directory be necessary at all if declaring a WantedBy param is supposed to instruct systemd to do that for you (as stated on the explanation of that parameter on this page)?

Can anyone shed light on the best way to configure multiple services using the same timer amid the confusing multiplicity of approaches to doing this?

SeligkeitIstInGott
  • 149
  • 2
  • 5
  • 18
  • So which one actually works for you? I created those service and timers in /usr/lib/systemd and use `systemctl --user start mytimer.timer`...it creates symbolic links under ~/.config/systemd/user – Khurshid Alam Aug 17 '17 at 13:50

2 Answers2

7

If you want to activate multiple services with a single timer insert a target in between:

The timer unit, let's call it foo.timer:

[Unit]
Description=My timer that runs saturdays, 9am and triggers foo.target

[Timer]
OnCalendar=Sat 9:00
Unit=foo.target

[Install]
WantedBy=timers.target

The target unit, let's call it foo.target:

[Unit]
Description= My target unit, that groups my two services xxx.service and yyy.service
Wants=xxx.service yyy.service
After=xxx.service yyy.service

[Install]
Also=foo.timer

And then the two services xxx.service and yyy.service:

[Unit]
Description=My service XXX

[Service]
ExecStart=/bin/echo I am XXX

[Install]
Also=foo.timer
[Unit]
Descritpion=My service YYY

[Service]
ExecStart=/bin/echo I am YYYY

[Install]
Also=foo.timer

Copy these four unit files (foo.timer, foo.target, xxx.service, yyy.service) into /etc/systemd/systemd/. Then enable and start the timer by issuing "systemctl enable --now foo.timer". That will hook foo.timer into timers.target, which is the generic target that is supposed to pull in all the various timers defined on a system. Note that you could as well do "systemctl enable foo.target" btw, and also "systemctl enable zzz.service", since the Also= lines in those units propagate the enablement requests towards foo.timer.

user175104
  • 181
  • 1
  • 2
  • This answer *seems* to work, but I can't get any timers triggered this way to fire more than once: https://serverfault.com/q/1079993/336913 – Paul Oct 11 '21 at 16:46
  • 1
    Looks like the problem was that the target unit should use `BindsTo=` instead of `Wants=` to bind to the services it's trying to group, otherwise the `.target` unit will stay active, preventing the timer from firing a second time. – Paul Oct 11 '21 at 17:54
0

A systemd timer always activates one unit.

If you want to activate two units on the same schedule, I recommend creating two timer files for clarity that contain the same schedule.

Otherwise, you could create a "service unit" file that launches the two services you want.

I don't think "WantedBy=" is a particularly useful concept for timer units.

Mark Stosberg
  • 3,771
  • 23
  • 27
  • So this is wrong? https://jason.the-graham.com/2013/03/06/how-to-use-systemd-timers/#running-multiple-scripts-on-the-same-timer – Khurshid Alam Aug 17 '17 at 13:29
  • The post offers fine advice, similar to mine. It's using a timer file to launch a single unit-- a "target". The target in turn uses a `WantedBy=` relationship to run two service files. That's a fine approach. – Mark Stosberg Aug 17 '17 at 15:04
  • My approach is to create few timer.tagets (hourly, daily etc) and then attach any services to those timers. For example, Service A-> hourly.timer, Service B & C -> 15 -min-timer...etc.....Although I am not sure which approach is more preferable. – Khurshid Alam Aug 17 '17 at 16:27