How to configure multiple systemd services to use one timer

systemd

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?

Best Answer

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.