如何编写bash脚本以便在进程死机时重新启动进程

2023-11-01 19:31:59 浏览数 (1)

问:

我有一个python脚本,它将检查队列并对每个元素执行操作:

代码语言:javascript复制
# checkqueue.py
while True:
  check_queue()
  do_something()

我如何编写一个bash脚本来检查它是否正在运行,如果没有,则启动它。大致如下伪代码(或者它应该做一些类似 ps | grep 的事情?)

代码语言:javascript复制
# keepalivescript.sh
if processidfile exists:
  if processid is running:
     exit, all ok

run checkqueue.py
write processid to processidfile
代码语言:javascript复制
我将从crontab中调用它:
代码语言:javascript复制
# crontab
*/5 * * * * /path/to/keepalivescript.sh

答:

避免使用 PID 文件、cron 或其他任何试图评估不属于其子进程的进程。

在UNIX中,有充分的理由只能等待子进程。任何试图解决这个问题的方法(ps解析、pgrep、存储PID等)都是有缺陷的,其中存在漏洞。待后文分析。

假设你的进程名为procA,监控它的进程名为procB,则需要procB成为procA的父进程。因为只有启动你的进程的进程才能可靠地等待它结束。而这在Bash中很容易实现。

代码语言:javascript复制
until procA; do
    echo "procA crashed with exit code $?. Restart..." >&2
    sleep 1
done

上面的bash代码在一个until循环中运行procA。第一行启动procA并等待它结束。当它结束时,until检查其退出状态。如果退出状态为0,则表示它正常结束(这意味着你要求它以某种方式关闭,并且它成功关闭了)。在这种情况下,我们不想重新启动它(我们只是要求它关闭!如果退出状态不是0,until将运行循环体,该循环体在STDERR上发出错误消息,并在 1 秒后重新启动循环(返回第 1 行)。

我们为什么要等一会儿?因为如果procA的启动顺序出了问题并立即崩溃,你将得到一个非常密集的循环,不断重新启动和崩溃。sleep 1消除了这种压力。

然后需要做的就是启动这个bash脚本,它将监控procA并在必要时重新启动它。如果你想在(操作系统)启动时启动监控脚本,你可以用@reboot规则在用户的 cron(1) 中调度它。使用crontab -e命令打开你的cron规则,然后添加一个规则来启动你的监控脚本:

代码语言:javascript复制
@reboot /usr/local/bin/procAmonitor

至于不使用PID文件的理由: 1. PID重用(可能导致杀死错误的进程)。 2. PID文件过时。你需要过于更复杂的逻辑来检查PID文件是否过时,而任何这样的逻辑都同样有1中的缺陷。 3. 如果你甚至没有写访问权限或者处于只读环境中该怎么办?

或者,查看systemd.unit(5)。你可以在/lib/systemd/system目录中添加一个名为procA.service的配置文件,让systemd进程监控你的procA。

代码语言:javascript复制
[Unit]
Description=Daemon for procA.

[Service]
ExecStart=/path/to/procA
Restart=on-failure
RestartSec=1s

[Install]
WantedBy=multi-user.target
然后再执行以下命令即可:
代码语言:javascript复制
systemctl daemon-reload
systemctl enable procA.service
代码语言:javascript复制

参考:

  • stackoverflow question 696839
  • man systemd.unit
  • man systemctl

0 人点赞