5

I think I have a relatively good handle on the different Type of services which systemd can be configured for (e.g. simple, oneshot, etc).

The docs provide a pretty reasonable overview and description of the options. So often it's possible to "guess" the likely best option and do 'trial and error' to confirm. That is especially the case with applications that I'm quite familiar with.

However, I am concerned that there may be circumstance I'm not accounting for during my 'trial and error' testing (i.e. risk of edge case bugs). So I'm after suggestions on methods of testing/investigating an application to determine it's likely best Type.

FWIW, I'm thinking of some way of manually launching an application and tracing how it responds, whether it forks or not (multiple processes, etc). I feel like there must be some relatively easy way to do that (using standard commandline tools) that I'm missing.

I'm not sure if it's relevant, but Debian is my distro of choice.

6
  • 3
    Joke on systemd: if there were "some relatively easy way to do that (using standard commandline tools)" they would have either (a) already incorporated that, or (b) re-invented it.
    – muru
    Oct 3, 2019 at 5:37
  • @muru That is pretty funny! :D Oct 3, 2019 at 5:57
  • 2
  • 2
    Also consider that often the right answer is not really derive Type from a program's behavior (e.g. Type=forking) but instead to modify the program's behavior (to not daemonize) in order to use a more appropriate Type (such as Type=simple). Also more integration with systemd is usually pretty beneficial and often enables powerful features (such as socket activation), so the best answer is that it's up to the developers to provide systemd units together with their code, so they can take full benefit of full integration.
    – filbranden
    Oct 3, 2019 at 9:47
  • 1
    Good point @filbranden. Obviously that's not so easy when working with someone else's software, although with FLOSS, improvements could always be contributed back. Oct 4, 2019 at 0:07

1 Answer 1

10

(Copied from my answer on Super User.SE.)

When you start the service manually from the command line (without using the nohupprefix command or the & suffix to run it in the background, or in other words, just run the command you would put on the ExecStart= line of the .service file), what happens?

a) If the service starts and keeps running, and the prompt does not return until you press Control-C or stop the service in some other way: then Type = simple is the right choice.

b) If the prompt returns but the service keeps running in the background (i.e. the service daemonizes itself on its own), then Type = forking is the right choice.

c) If the service does its job and returns to the prompt without leaving anything running (i.e. the service just adjusts some kernel settings, sends a command to something else or does something similar), then Type = oneshot is probably the right choice. In this case, ExecStart of the service might be the command to "set" something, and ExecStop would be the corresponding command to "unset" it. This type usually benefits of RemainAfterExit=true, so systemd will keep track of the "state" of this service according to whether the thing was most recently "set" or "unset".

The other Type values are special cases. For example, if the service utilizes a D-Bus connection, then Type = dbus might be the best choice. It makes systemd aware of the fact, and then systemd will track this service (and anything that depends on it) by the presence of this service on the D-Bus.

To use Type = notify, the process must be able to connect to Unix socket specified in environment variable $NOTIFY_SOCKET and to report its status by writing messages to that socket whenever necessary. Also, the service file should specify the NotifyAccess option to grant access to the notification socket as appropriate.

There is a command-line utility systemd-notify and a C library function sd_notify(3) you may use to send these messages, but if neither of those is suitable to your requirements, you can just implement your own message sender. The messages required are very simple, and look like shell variable assignments: for example, to notify that the service has successfully completed startup and is ready to serve any incoming requests, the service should send the string equivalent to the output of printf "READY=1\n" to the socket. See man 3 sd_notify for more details on the recognized messages.

Note: many service applications designed to be portable to many Unix-style systems may behave as b) by default, but can be made to work like a) by adding an option (usually described as "don't fork", "keep running in foreground", "don't daemonize" or similar). In that case, if the option has no other side effects, then adding the option and using the a)-type behavior would be preferable for systemd.

9
  • I've got "ExecStart=/usr/bin/sudo -u someuser /usr/bin/someprogram" with "PIDFile=/var/run/somefile". Using "Type=Simple" prints "Supervising process XXXX which is not our child. We'll most likely not notice when it exits", but "Type=Forking" hangs until it times out because the sudo doesn't exit. Which type should I use instead?
    – PFudd
    Jan 16 at 21:16
  • @PFudd Instead of using sudo -u someuser as part of the ExecStart= command, specify the user directly in the service definition as User=someuser. If the program requires something in someuser's login script, find out what it is, and add the necessary environment settings, ulimits, etc. to the service definition. Making the program's requirements explicit like that may take some effort, but you'll thank yourself later when it's time to move your setup to a new major OS release or new hardware.
    – telcoM
    Jan 16 at 21:37
  • The reason I switched from User=someuser to User=root is because the program expects /var/run/someprogram to exist. The ExecStartPre= line now says /usr/bin/install -d -o someuser -g somegroup -m 755 /var/run/someprogram. I used to have it say ExecStartPre=+/usr/bin/install..., but the + feature isn't available on older versions of systemd.
    – PFudd
    Jan 16 at 22:04
  • For the curious, someprogram is zabbix_agent2 and someuser is zabbix. The version of systemd that doesn't have the + feature is 219. A version of systemd with that feature is 249. Zabbix expects /var/run/zabbix to exist and be writable by the zabbix user, but on Ubuntu 22.04 (at least), /var/run is a tmpfs.
    – PFudd
    Jan 16 at 22:11
  • The zabbix-agent2 package creates /var/run/zabbix on install and expects it to live forever. Oh, and the + feature means "run this command with full privileges" (i.e. as root).
    – PFudd
    Jan 16 at 22:16

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .