Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Letting other users stop/restart simple bash daemons – use signals or what?

I have a web server where I run some slow-starting programs as daemons. These sometimes need quick restarting (or stopping) when I recompile them or switch to another installation of them.

Inspired by http://mywiki.wooledge.org/ProcessManagement, I'm writing a script called daemonise.sh that looks like

#!/bin/sh
while :; do
    ./myprogram lotsadata.xml
    echo "Restarting server..." 1>&2
done

to keep a "daemon" running. Since I sometimes need to stop it, or just restart it, I run that script in a screen session, like:

$ ./daemonise.sh & DPID=$!
$ screen -d

Then perhaps I recompile myprogram, install it to a new path, start the new one up and want to kill the old one:

$ screen -r
$ kill $DPID
$ screen -d

This works fine when I'm the only maintainer, but now I want to let someone else stop/restart the program, no matter who started it. And to make things more complicated, the daemonise.sh script in fact starts about 16 programs, making it a hassle to kill every single one if you don't know their PIDs.

What would be the "best practices" way of letting another user stop/restart the daemons?

I thought about shared screen sessions, but that just sounds hacky and insecure. The best solution I've come up with for now is to wrap starting and killing in a script that catches certain signals:

#!/bin/bash
DPID=
trap './daemonise.sh & DPID=$!' USR1
trap 'kill $DPID' USR2 EXIT

# Ensure trapper wrapper doesn't exit:
while :; do
    sleep 10000 & wait $!
done

Now, should another user need to stop the daemons and I can't do it, she just has to know the pid of the wrapper, and e.g. sudo kill -s USR2 $wrapperpid. (Also, this makes it possible to run the daemons on reboots, and still kill them cleanly.)

Is there a better solution? Are there obvious problems with this solution that I'm not seeing?

(After reading Greg's Bash Wiki, I'd like to avoid any solution involving pgrep or PID-files …)

like image 469
unhammer Avatar asked Feb 24 '12 15:02

unhammer


People also ask

What signals will stop a program no matter what?

For example, SIGKILL is the signal sent when a process should be terminated. The kernel will see that the process has been sent this signal and terminate the process from running, no questions asked.

How do I stop the daemon process?

Issue the kill -15 command with the process identifier number to stop the daemons. For AIX® and Linux x86_64 GPFS™ file systems, issue the command dmkilld to stop the recall daemons. Verify that the daemons are no longer running.

Which signal is commonly sent to a daemon to request it to restart with a new configuration file?

Most daemons are written to respond to the SIGHUP signal by re-reading their configuration file. So instead of killing and restarting httpd you would send it the SIGHUP signal.

What command signal do you use to terminate a process?

“ kill -9” command sends a kill signal to terminate any process immediately when attached with a PID or a processname. It is a forceful way to kill/terminate a or set of processes. “ kill -9 <pid> / <processname>” sends SIGKILL (9) — Kill signal. This signal cannot be handled (caught), ignored or blocked.


2 Answers

I recommend a PID based init script. Anyone with sudo privileged to the script will be able to start and stop the server processes.

like image 78
reconbot Avatar answered Nov 15 '22 04:11

reconbot


On improving your approach: wouldn't it be advisable to make sure that your sleep command in sleep 10000 & wait $! gets properly terminated if your pidwrapper script exits somehow?

Otherwise there would remain a dangling sleep process in the process table for quite some time.

Similarly, wouldn't it be cleaner to terminate myprogram in daemonise.sh properly on restart (i. e. if daemonise.sh receives a TERM signal)?

In addition, it is possible to suppress job notification messages and test for pid existence before killing.

#!/bin/sh
# cat daemonise.sh

# cf. "How to suppress Terminated message after killing in bash?",
# http://stackoverflow.com/q/81520

trap '
   echo "server shut down..." 1>&2
   kill $spid1 $spid2 $spid3 &&
      wait  $spid1 $spid2 $spid3 2>/dev/null
   exit
' TERM

while :; do
    echo "Starting server..." 1>&2
    #./myprogram lotsadata.xml
    sleep 100 &
    spid1=${!}
    sleep 100 &
    spid2=${!}
    sleep 100 &
    spid3=${!}
    wait
    echo "Restarting server..." 1>&2
done

#------------------------------------------------------------

#!/bin/bash
# cat pidwrapper

DPID=

trap '
   kill -0 ${!} 2>/dev/null && kill ${!} && wait ${!} 2>/dev/null
   ./daemonise.sh & DPID=${!}
' USR1

trap '
   kill -0 ${!} 2>/dev/null && kill ${!} && wait ${!} 2>/dev/null
   kill -0 $DPID 2>/dev/null && kill $DPID && wait ${DPID} 2>/dev/null
' USR2 

trap '
   trap - EXIT
   kill -0 $DPID 2>/dev/null && kill $DPID && wait ${DPID} 2>/dev/null
   kill -0 ${!} 2>/dev/null && kill ${!} && wait ${!} 2>/dev/null
   exit 0
' EXIT

# Ensure trapper wrapper does not exit:
while :; do
    sleep 10000 & wait $!
done

#------------------------------------------------------------

# test

{
wrapperpid="`exec sh -c './pidwrapper & echo ${!}' | head -1`"
echo "wrapperpid: $wrapperpid"
for n in 1 2 3 4 5; do
   sleep 2
   # start daemonise.sh
   kill -s USR1 $wrapperpid 
   sleep 2
   # kill daemonise.sh
   kill -s USR2 $wrapperpid 
done
sleep 2
echo kill $wrapperpid
kill $wrapperpid
}
like image 26
nuro Avatar answered Nov 15 '22 06:11

nuro