3

I have two systemd services a and b, where b is "After" and "BindsTo" a, and b is a short command that is launched every minute with a systemd timer.

Heres my config:

$ cat /systemd/a.service
[Unit]
After=foo
BindsTo=foo

[Service]
ExecStart=/opt/a/bin/a
Group=lev
User=lev
Restart=Always
WorkingDirectory=/opt/a

$ cat /systemd/b.service
[Unit]
After=a
BindsTo=a

[Service]
ExecStart=/opt/b/bin/b
Group=lev
User=lev
WorkingDirectory=/opt/b

$ cat /systemd/b.timer
[Unit]

[Timer]
OnCalendar=*:0/1:00

When I run sudo systemctl stop a, service a is indeed stopped, but then it is started back up at the top of the next minute when the timer for service b runs b

The systemd documentation states that BindsTo

declares that if the unit bound to is stopped, this unit will be stopped too.

(https://www.freedesktop.org/software/systemd/man/systemd.unit.html#BindsTo=)

I expect that by stopping a, b will also be stopped, and the timer disabled. This is not the case. Can you help explain why the b timer restarts not only b (which should fail), but also a?

Can you also help me edit these services such that:

  • on boot, a is started first, then b is started
  • when I sudo systemctl stop a, b's timer does not run
  • when I sudo systemctl start a, b's timer begins running again

Thanks in advance!

Lev Dubinets
  • 788
  • 10
  • 32

2 Answers2

1

Here are the simplest units that meet your constraints:

test-a.service

[Service]              
ExecStart=sleep 3600  # long-running command

test-b.service

[Service]     
ExecStart=date  # short command

test-b.timer

[Unit]                                
After=test-a.service
BindsTo=test-a.service   # makes test-b.timer stop when test-a.service stops
                                      
[Timer]                                           
OnCalendar=* *-*-* *:*:00             
                                      
[Install]                             
WantedBy=test-a.service  # makes test-b.timer start when test-a.service starts

Don't forget to

  • systemctl daemon-reload
  • systemctl disable test-b.timer
  • systemctl enable test-b.timer To apply the changes in the [Install] section.

Explanations:

  • what you want is to bind a.service with b.timer, not b.service
  • b.service is only a short command, and systemctl start b.service will only run the command, not start the associated timer
  • only systemctl start b.timer will start the timer
  • The WantedBy tells systemd to start test-b.timer when test-a.service starts
  • The BindsTo tells test-b.timer to stop when test-a.service stops
  • The After only ensures that test-b.timer is not started at the same time than test-a.service: it will force systemd to start test-b.timer after test-a.service has finished starting.

About the behaviour you observed:

  • When you stopped your a.service, the b.timer was still active and it tried starting b.service to run its short command. Since your b.service specified BindsTo=a.service, systemd thought that b.service required a.service to be started also, and effectively restarted a.service for b.service to run correctly.
duthils
  • 1,181
  • 3
  • 7
  • Thanks @duthils - I was also suspecting that I needed a `BindsTo` on the timer but I couldn't find any documentation indicating that timers actually support `BindsTo`. Did you try this yourself and does it work? I will spend some time this week trying it as well. – Lev Dubinets Jul 01 '20 at 23:33
  • I did try it, and the timer was correctly started and stopped at the same time than the bound service. As far as systemd is concerned, timers and services are both units and every setting in the `[Unit]` section is applicable to any unit. – duthils Jul 03 '20 at 01:52
-1

I could be mistaken, but I believe that the "Restart=Always" option is the reason that the service named a is started and hence why the service named b is not subsequently stopped.

The man page for systemd.service states if this option is set to always

the service will be restarted regardless of whether it exited cleanly or not, got terminated abnormally by a signal, or hit a timeout.

https://www.freedesktop.org/software/systemd/man/systemd.service.html#Restart=

So even though you are stopping the service, this option is starting it again.

You can test this by running the following commands. Since you have service "b" on a one minute timer, I would run the stop command at 10 seconds after the top of the minute (i.e. 10:00:10). Then I would run the status command 20 seconds later and see if the service has been restarted.

sudo systemctl stop a sudo systemctl status a b

ottokram
  • 1
  • 1
  • See in your linked documentation: `As exceptions to the setting above, the service will not be restarted if ... the service is stopped with systemctl stop or an equivalent operation` – Lev Dubinets Jul 01 '20 at 23:31