Systemd – restart without stop

systemd

I have a small problem. I have one program (let's call it master) which, internally, starts several programs (client1, client2 and client3) and detaches them.

Now, I want the main program to always stay online, so I wrote a systemd service file like this:

[Unit]
Description=Run the master
Before=runlevel2.target runlevel3.target runlevel4.target runlevel5.target
After=remote-fs.target systemd-journald-dev-log.socket all.target

[Service]
Type=forking
Restart=always
TimeoutSec=5min
IgnoreSIGPIPE=no
KillMode=process
RemainAfterExit=no
SysVStartPriority=5
ExecStart=/home/user/start_master.sh start
ExecStop=/home/user/start_master.sh stop
PIDFile=/var/run/mymaster.pid

[Install]
WantedBy=multi-user.target

The starting script is like this one:

#! /bin/sh

PIDFILE=/var/run/mymaster.pid

do_start() {
    /home/user/master >/dev/null 2>&1 &
    echo $!
}

case "$1" in
    start)
        PID=$(do_start)
        if [ -z $PID ]; then
                echo "Failed starting master"
                exit 2
        else
                echo $PID > $PIDFILE
        fi
        ;;
    stop)
        killall master client1 client2 client3 2>/dev/null
        rm $PIDFILE
        ;;
    restart)
        killall master 2>/dev/null
        $0 start
        ;;
    *)
        echo "Usage: $0 start|stop|restart" >&2
        exit 3
        ;;
esac

My desired behavior is:

  • on start: just start the master (it will take care of starting the clients)
  • on restart (or when the master is shut down): kill the master program and restart it (since it will attach to the previous clients)
  • on stop: kill the master program and all the clients

Now, with this setup, everything works fine: when I start the service, this is what I see:

$ systemctl status master.service
● master.service - Run the master
   Loaded: loaded (/etc/systemd/system/master.service; enabled)
   Active: active (running) since Wed 2016-10-19 16:16:33 CEST; 5s ago
  Process: 4161 ExecStop=/home/user/start_master.sh stop (code=exited, status=0/SUCCESS)
  Process: 4198 ExecStart=/home/user/start_master.sh start (code=exited, status=0/SUCCESS)
 Main PID: 4200 (master)
   CGroup: /system.slice/master.service
           ├─4200 /home/user/master
           ├─4203 /home/user/client1
           ├─4205 /home/user/client2
           └─4209 /home/user/client3

Also the stop runs fine. BUT… when I want to restart it (either by calling restart or by manually killing the master program) systemd executes the ExecStop instead of the restart command, thus killing all the clients too.

Is there a way to achieve what I wanted?

Best regards

PS. I'm using Debian 8.6.0 x64

Best Answer

systemd does not have a notion of a restart that is not just stop-if-running+start. You might be able to use ExecReload= and then use systemctl reload instead of restart, but the question is why you need this?

Why do you restart the master without restarting the clients? For that matter, what does the master actually do? Your start script leads me to believe that you are trying to do process supervision again, which I would advise against - systemd can do that, so use it.

I would recommend that you instead try to figure out how you can start the clients via systemd.

In any case, your start script is completely superfluous. It uses PID files and all sorts of stuff that is absolutely unnecessary because systemd can already do all that stuff. I suggest removing it and instead just using "ExecStart=/home/user/master" in your .service file (if the master is necessary after all), then adjust the Type= from "forking" to "simple". Remove the "ExecStop" and "PIDFile".

I recommend https://jdebp.eu/FGA/systemd-house-of-horror/tomcat.html as further reading.

Related Question