2

I have a very complex python application. It has it's own init script, but when I execute:

sudo service my_service_daemon stop

It prints "Stopping my_service_daemon [OK]", but in real subprocesses still alive, until they finish their work (they caught signal 15, but have to finish some job). So, I want that message "[OK]" will be printed only when there are no subprocesses at all. Here is part of init script (it runs on CentOS 6)

...

. /etc/init.d/functions 

...

stop(){
    echo -n $"Stopping $prog: "
    if [ -a $pidfile ]; then
    group_id=$(ps -o pgid= $(cat $pidfile) | grep -o [0-9]*)
    if [ ! -z $group_id ]; then
            kill -- -$group_id
        success
    fi
    else
        failure
    fi
    RETVAL=$?
    echo
    [ $RETVAL = 0 ] && rm -f $lockfile $pidfile
}
2
  • Poll the count of ps -o pid= --ppid $(cat $pidfile), maybe?
    – muru
    Oct 20, 2015 at 17:55
  • It seems like also working, could you provide some explanation? What a difference from that solution with pgrep?
    – Sergius
    Oct 21, 2015 at 8:05

3 Answers 3

3

Use systemd's handling of processes, or use a cgroup by hand to control the zoo of decendents. Fooling around with ps(1) output and PID files is race-prone, and has been known to lead to early baldness due to hair-pulling.

1
  • 2
    systemd? but it has sysvinit as init system, also it's a /etc/init.d/my_service_daemon script... or I misunderstand something?
    – Sergius
    Oct 21, 2015 at 7:50
1

After you do the kill -- -$group_id wait for all the processes to end. For example, I'd do something like

...
if [ ! -z "$group_id" ]; then
    kill -- -$group_id
    while pgrep -g $group_id &>/dev/null; do
        sleep 1
    done
    success
...

This will have pgrep search for all members of the process group (-g) $group_id. Normally it will print all those PIDs to the screen, but we don't really want to see them so I redirect all the output to /dev/null. pgrep will exit with success (0) if it finds at least 1 process matching its search criteria, which would keep the while loop going. Once it doesn't find any processes it will exit with a "false" (1) which will exit the loop and get to the success line. In order to not crush the system with a tight loop, I stuck a sleep 1 in there.

2
  • It seems, like it really helps! Could you please, provide some explanation? I've never used pgrep
    – Sergius
    Oct 21, 2015 at 8:00
  • @Sergius I've updated my answer with some explanation of how it works Oct 21, 2015 at 12:01
1

Keep a file open in the Python application. That is, open it in the launcher script, and don't close it in the application.

This file can be the PID file. Proof of concept (with no handling of concurrency):

pidfile=/var/run/myapp.pid
logfile=/var/log/myapp.log
start () {
  sh -c 'echo $$ >"$1"; exec myapp <"$1" >/dev/null 2>"$2"' &
}
stop () {
  master_pid=$(cat "$pidfile")
  while
    case " $(fuser "$pidfile" 2>/dev/null) " in
      *" $master_pid "*)
        echo "Master process is alive, killing it"
        kill "$master_pid";;
      "  ") echo "Master process is dead and no subprocesses remain"; false;;
      *) echo "Master process is already dead but some processes remain";;
    esac
  do
    sleep 1
  done
  rm "$pidfile"
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.