我有一个非常复杂的 python 应用程序。它有自己的初始化脚本,但是当我执行时:
sudo service my_service_daemon stop
它打印“Stopping my_service_daemon [OK]”,但在实际子进程中仍然存在,直到它们完成工作(它们捕获信号 15,但必须完成一些工作)。因此,我希望仅当根本没有子进程时才会打印消息“[OK]”。这是初始化脚本的一部分(它在 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
}
答案1
使用systemd
进程的处理,或者使用手动cgroup
来控制后代的动物园。乱搞输出ps(1)
和 PID 文件很容易引发竞赛,并且已知会因拉扯头发而导致过早秃顶。
答案2
完成后等待kill -- -$group_id
所有进程结束。例如,我会做类似的事情
...
if [ ! -z "$group_id" ]; then
kill -- -$group_id
while pgrep -g $group_id &>/dev/null; do
sleep 1
done
success
...
这将pgrep
搜索进程组 ( -g
)的所有成员$group_id
。通常它会将所有这些 PID 打印到屏幕上,但我们并不想看到它们,所以我将所有输出重定向到/dev/null
. 如果找到至少 1 个与其搜索条件匹配的进程,pgrep
则将成功退出 ( ),这将保持循环继续。一旦它没有找到任何进程,它将以“false”( ) 退出,这将退出循环并到达该行。为了不因紧密循环而破坏系统,我在其中插入了一个。0
while
1
success
sleep 1
答案3
在 Python 应用程序中保持文件打开。也就是说,在启动器脚本中打开它,并且不要在应用程序中关闭它。
该文件可以是PID文件。概念证明(不处理并发):
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"
}