让其他用户停止/重新启动简单的 bash 守护进程 –使用信号还是什么?

发布于 2025-01-08 11:01:48 字数 1296 浏览 0 评论 0原文

我有一个网络服务器,我在其中运行一些启动缓慢的程序作为守护进程。当我重新编译它们或切换到它们的另一个安装时,有时需要快速重新启动(或停止)。

受到 http://mywiki.wooledge.org/ProcessManagement 的启发,我正在编写一个脚本 名为 daemonise.sh ,看起来像是

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

保持“守护进程”运行。因为我有时需要停止它,或者只是 重新启动它,我在屏幕会话中运行该脚本,例如:

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

然后也许我重新编译我的程序,将其安装到新路径,开始 新的出现并想杀死旧的:

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

当我是唯一的维护者时,这很好用,但现在我想让 其他人停止/重新启动该程序,无论是谁启动的。和 让事情变得更复杂的是,事实上 daemonise.sh 脚本 启动大约 16 个程序,杀死每一个程序都很麻烦 如果你不知道他们的 PID。

让另一个用户的“最佳实践”方式是什么 停止/重新启动守护进程?

我考虑过共享屏幕会话,但这听起来很老套 没有安全感。我现在想出的最好的解决方案是包装 在捕获某些信号的脚本中启动和终止:

#!/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

现在,如果另一个用户需要停止守护进程而我却做不到, 她只需要知道包装器的 pid,例如 sudo Kill -s USR2 $wrapperpid。 (此外,这使得运行守护进程成为可能 重新启动后,仍然可以干净地杀死它们。)

有更好的解决方案吗?这是否存在明显的问题 我没有看到的解决方案?

(阅读 Greg 的 Bash Wiki 后,我想避免任何涉及 pgrep 或 PID 文件的解决方案……)

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 …)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

别再吹冷风 2025-01-15 11:01:48

我推荐一个基于 PID 的初始化脚本。任何拥有该脚本 sudo 权限的人都可以启动和停止服务器进程。

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

扶醉桌前 2025-01-15 11:01:48

关于改进您的方法:确保您的 sleep 命令在 sleep 10000 & 中不是明智的吗?如果您的 pidwrapper 脚本以某种方式退出, wait $! 会正确终止吗?

否则,进程表中将保留一个悬空的睡眠进程相当长的一段时间。

同样,重新启动时正确终止 daemonise.sh 中的 myprogram 不是更干净吗(即,如果 daemonise.sh 收到 TERM 信号)?

此外,还可以抑制作业通知消息并在杀死之前测试 pid 是否存在。

#!/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
}

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
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文