如何在失败时自动重启Python脚本?

5 投票
4 回答
5672 浏览
提问于 2025-04-15 22:02

这篇文章讲的是如何在BASH脚本中保持一个子进程一直运行:

我该如何写一个BASH脚本来在进程崩溃时重启它?

这个方法在调用另一个BASH脚本时效果很好。

不过,我尝试执行类似的操作,子进程是一个Python脚本,叫做daemon.py,它会创建一个在后台运行的分叉子进程:

#!/bin/bash

PYTHON=/usr/bin/python2.6

function myprocess {


$PYTHON daemon.py start

}
NOW=$(date +"%b-%d-%y")

until myprocess; do
     echo "$NOW Prog crashed. Restarting..." >> error.txt
     sleep 1
done

现在情况完全不同。看起来这个Python脚本不再是BASH脚本的子进程,而是似乎“接管”了BASH脚本的进程ID(PID)——所以调用的脚本周围不再有BASH的包裹……这是为什么呢?

4 个回答

0

看起来这里的行为完全不同,因为你的“daemon.py”是作为一个后台进程启动的。

而在你提到的另一个链接中,被监控的进程不是一个后台进程,它不会在后台启动。启动程序只是一直等待,直到子进程结束。

有几种方法可以解决这个问题。最常见的方法是@Alex提到的,使用一些在常规位置的pid文件。

另一种方法是把监控程序放在你正在运行的后台进程里面,并让监控程序也变成后台进程……这样可以模拟一个正常的进程,不会随机中断(这种情况是不应该发生的)……

3

你可以看看Python改进提案3143(PEP),在这里可以找到。里面Ben建议在Python的标准库中加入一个守护进程库。他详细讲了很多关于守护进程的好信息,读起来也比较简单。参考实现可以在这里找到。

5

守护进程会进行双重分叉,这是让它变成守护进程的关键步骤——所以,父进程的进程ID(PID)就没什么用了(因为在子进程启动后不久,它就消失了)。

因此,守护进程应该把它的PID写入一个“大家都知道的位置”的文件里,按照惯例,父进程知道从哪里去读取这个PID;通过这种(传统的)方式,父进程如果想要充当一个重启监视器,就可以简单地从这个大家都知道的位置读取守护进程的PID,并定期检查这个守护进程是否还在运行,如果需要的话就重启它。

当然,这个过程需要一些小心(因为一个“过时”的PID会在这个“大家都知道的位置”的文件里存在一段时间,父进程必须考虑到这一点),而且还有一些变种(守护进程可以发出一个“心跳信号”,这样父进程不仅能检测到死掉的守护进程,还能发现那些“卡住了”的守护进程,比如因为死锁而停止发出“心跳信号”[[通过UDP广播或类似方式]]——等等等等),但这就是大致的思路。

撰写回答