A perhaps surprising consequence of Requires dependencies in systemd

December 26, 2016

I tweeted:

Oh right. This service restarted because I said 'Requires=rsyslog.service' & I updated rsyslogd (which restarted it). Moral: don't do that.

The systemd.unit manpage tells you that this will happen if you read it carefully. In the section on Requires:

If this unit gets activated, the units listed here will be activated as well. If one of the other units gets deactivated or its activation fails, this unit will be deactivated.

(Italics mine.)

When you or a package upgrade script does a 'systemctl restart rsyslog', rsyslog is first deactivated, which triggers the deactivation of my service, and then it is reactivated, which fortunately results in the reactivation of my service too (because systemd is not completely moronic, regardless of what people may think of it).

The important thing to remember here is that Requires has two effects. The first is that it forces the required unit to start on boot (or activation of your unit) and will stop your unit from starting if the required unit fails for some reason. So what I was saying is 'my unit must have rsyslogd in order to start and work'. The other, as we saw here, is that your unit will be deactivated or restarted if its required unit fails or is restarted.

This restart behavior is not as crazy as it may sound. There are services which are strongly linked and that don't recover transparently from having their communication to a required service broken; one traditional example is portmap. In classical NFS, the various services that use SUNRPC registered with portmap exactly once, when they started. If portmap was restarted, those registrations were lost and could not be re-established short of restarting all the other services too. This is a perfect fit for a systemd Requires relationship.

(I believe this has been changed in modern SUNRPC code, for the obvious reason that it's kind of suboptimal.)

Unfortunately I don't believe that systemd has a form of requirement that just does the initial boot time requirement stuff without the 'restart your service when a Requires restarts' bit. Wants is not quite it because it doesn't stop your unit from starting if its requirement doesn't. It's thus more useful for dependencies that you would really like to be running but you don't absolutely totally require.

Probably what I should do for this service is shift my requirement over to the general syslog.socket, although that's not currently activated on my system and I'm not completely sure it's the right thing.

(It turns out that SUNRPC is now officially called ONC PRC, presumably because 'Sun' is a trademark and no one wanted to embed a trademark in the name of an official standard that was theoretically supposed to be vendor-neutral.)


Comments on this page:

By Chris at 2016-12-27 17:35:36:

You could use wants to load the unit (hopefully), and then AssertFileNotEmpty=/run/rsyslogd.pid to make it fail if rsyslog didn't start.

I assume the systemd behaviour would also avoid dropping any log messages. Particularly if this script ran as a daemon.

It's another reason why it would be nice to solve this using socket activation. (Systemd claims to allow daemon restarts without dropping any datagram messages).

Written on 26 December 2016.
« Some new-to-me Vim motion commands that I want to try to remember
The HTML IMG attributes and styling that I think I want »

Page tools: View Source, View Normal, Add Comment.
Search:
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Mon Dec 26 22:55:53 2016
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.