如果进程死了,如何编写 bash 脚本来重新启动进程?

新手上路,请多包涵

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

 # checkqueue.py
while True:
  check_queue()
  do_something()

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

 # keepalivescript.sh
if processidfile exists:
  if processid is running:
     exit, all ok

run checkqueue.py
write processid to processidfile

我将从 crontab 中调用它:

 # crontab
*/5 * * * * /path/to/keepalivescript.sh

原文由 Tom 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 797
2 个回答

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

在 UNIX 中,您只能等待您的孩子,这是有充分理由的。任何试图解决这个问题的方法(ps 解析、pgrep、存储 PID,…)都是有缺陷的,并且存在漏洞。只是 说不

相反,您需要将监控您的进程的进程作为该进程的父进程。这是什么意思?这意味着只有 启动 你的进程的进程才能可靠地等待它结束。在 bash 中,这绝对是微不足道的。

 until myserver; do
    echo "Server 'myserver' crashed with exit code $?.  Respawning.." >&2
    sleep 1
done

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

我们为什么要等一秒钟?因为如果 myserver 的启动顺序出现问题并且它立即崩溃,您将有一个非常密集的循环不断重启和崩溃。 sleep 1 消除了压力。

现在您需要做的就是启动这个 bash 脚本(可能是异步的),它将监控 myserver 并在必要时重新启动它。如果您想在启动时启动监视器(使服务器“存活”重新启动),您可以使用 @reboot 规则将其安排在用户的 cron(1) 中。使用 crontab 打开您的 cron 规则:

 crontab -e

然后添加一个规则来启动你的监控脚本:

 @reboot /usr/local/bin/myservermonitor


或者;查看 inittab(5) 和 /etc/inittab。您可以在其中添加一行以使 myserver 从某个初始化级别开始并自动重生。


编辑。

让我添加一些关于为什么 使用 PID 文件的信息。虽然它们很受欢迎;他们也有很大的缺陷,你没有理由不以正确的方式去做。

考虑一下:

  1. PID回收(杀错进程):

    • /etc/init.d/foo start :开始 foo ,写入 foo 的PID到 /var/run/foo.pid
    • 过了一会儿: foo 不知何故死了。
    • 稍后:任何启动的随机进程(称为 bar )都采用随机 PID,想象一下它采用 foo 的旧 PID。
    • You notice foo ’s gone: /etc/init.d/foo/restart reads /var/run/foo.pid , checks to see if it’s still alive, finds bar , thinks it’s foo ,杀死它,开始一个新的 foo
  2. PID 文件过时。您需要过于复杂(或者我应该说,非平凡的)逻辑来检查 PID 文件是否过时,并且任何此类逻辑再次容易受到 1. 的攻击。

  3. 如果您甚至没有写访问权限或处于只读环境中怎么办?

  4. 这是毫无意义的过度复杂化;看看我上面的例子是多么简单。完全没有必要把它复杂化。

另请参阅: “正确”执行时,PID 文件是否仍然存在缺陷?

顺便一提; 比 PID 文件更糟糕的是解析 ps 永远不要这样做。

  1. ps 非常不便携。虽然您几乎可以在每个 UNIX 系统上找到它;如果您想要非标准输出,它的参数会有很大差异。标准输出仅供人类使用,不能用于脚本解析!
  2. 解析 ps 会导致大量误报。以 ps aux | grep PID 示例为例,现在想象有人以某处的数字作为参数启动一个进程,该参数恰好与您盯着守护程序使用的 PID 相同!想象一下,两个人开始一个 X 会话,而你正在寻找 X 来杀死你的会话。这只是各种各样的坏事。

如果您不想自己管理流程;有一些非常好的系统可以作为您流程的监控器。例如,查看 runit

原文由 lhunath 发布,翻译遵循 CC BY-SA 3.0 许可协议

看看 monit ( http://mmoni.com/monit/ )。它处理脚本的启动、停止和重新启动,并且可以在必要时进行健康检查和重新启动。

或者做一个简单的脚本:

 while true
do
/your/script
sleep 1
done

原文由 Bernd 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题