2

I'm trying to convert a SysV init script to systemd. The SysV configuration is spawning different process in such a way:

su -l $USER_A -c "$CMD_A &"
usleep 600000
su -l $USER_B -c "$CMD_B &"
usleep 100000
su -l $USER_C -c "$CMD_C &"
usleep 300000

Because all spawn processes are using a different user, I've been creating a systemd service unit for each of them. In this service unit, I've specified the dependency (using Requires+After). E.g. of one of those service unit:

[Unit]
Description=CMD_B
Requires=CMD_A
After=CMD_A

[Service]
User=USER_B
Type=simple
ExecStart=/FULLPATH/CMD_B

[Install]
WantedBy=multi-user.target

The problem is that the different processes are communication via POSIX queues and those queues are not instantly created, so they need some period of time between each launch because they are not robust enough to wait for the POSIX queues to be created, they just failed :-(

I can't change those processes so I'm stuck with adding this elapsed time between the launch of each service.

How can I "cleanly" tell systemd that it should consider specific time period between each service activation?

Note: Although systemd respect the "After" dependency, as I think it considers those commands as immediately active, they are spawn almost at the same time (within a few ms). If I try to add an ExecStartPost=/usr/bin/usleep 600000 it seems that they are also all spawn with in a few ms, because the type of the service is simple, I guess that ExecStartPost is never triggered. So I have tried ExecStartPre=/usr/bin/usleep 600000 (for CMD_B, and I changed to 100000 for CMD_C) but it seems that the order is now no longer respected, CMD_A was first started, then CMD_C after 100ms and finally CMD_B after 600ms. So CMD_C failed because it was started before CMD_B. I have now use this ExecStartPre= trick but I've chosen 600ms for CMD_B, 700ms for CMD_C, etc. It works but I found that terribly awful.

Huygens
  • 9,345

1 Answers1

2

I would like to propose a method that does not use timeouts, but rather relies on systemd's mechanism for waiting on a file to exist before launching a program.

As you know, Linux can expose posix message queues as files. On my Fedora system it does so by default in /dev/mqueue/, but you can create the directory and mount -t mqueue none /dev/mqueue if you don't have it.

Then you can use (see man systemd.path) a simple unit myqueueb.path like this:

[Path]
PathExists=/dev/mqueue/queueb
[Install]
WantedBy=multi-user.target

and another myqueueb.service of the same name (or set Unit= in the above) with

[Unit]
Description=CMD_B
[Service]
User=USER_B
Type=simple
ExecStart=/FULLPATH/CMD_B

to do what you want. Do NOT enable the 2nd unit, but do systemctl enable myqueueb.path and systemctl start myqueueb.path. This sets up an inotifywait on the file /dev/mqueue/queueb.

When your first program creates message queue queueb, this file will appear and systemd will automatically start myqueueb.service and run your program CMD_B. Obviously you need to change these names to match your queue names and relationships for CMD_C as well.

meuh
  • 51,383
  • That's a great idea! I will to implement it and see if it works well for that program! – Huygens Nov 09 '15 at 17:37
  • It works fine, thank you very much. I do still have 1 trouble with one of the process, I guess I don't have the right path dependency, I need to see that with the devs... Merci bien ! – Huygens Nov 10 '15 at 12:32
  • According to http://unix.stackexchange.com/a/297835/9689 there is no multi-user.target , is it? Otherwise, could someone, please correct example with better target? – Grzegorz Wierzowiecki Jul 31 '16 at 15:43
  • @GrzegorzWierzowiecki the question you linked is referring to a per-user systemd instance. multi-user.target is valid for system-level services. – thinkmassive Dec 18 '17 at 17:55