如何在失败时自动重启Python脚本?
这篇文章讲的是如何在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 个回答
看起来这里的行为完全不同,因为你的“daemon.py”是作为一个后台进程启动的。
而在你提到的另一个链接中,被监控的进程不是一个后台进程,它不会在后台启动。启动程序只是一直等待,直到子进程结束。
有几种方法可以解决这个问题。最常见的方法是@Alex提到的,使用一些在常规位置的pid文件。
另一种方法是把监控程序放在你正在运行的后台进程里面,并让监控程序也变成后台进程……这样可以模拟一个正常的进程,不会随机中断(这种情况是不应该发生的)……
守护进程会进行双重分叉,这是让它变成守护进程的关键步骤——所以,父进程的进程ID(PID)就没什么用了(因为在子进程启动后不久,它就消失了)。
因此,守护进程应该把它的PID写入一个“大家都知道的位置”的文件里,按照惯例,父进程知道从哪里去读取这个PID;通过这种(传统的)方式,父进程如果想要充当一个重启监视器,就可以简单地从这个大家都知道的位置读取守护进程的PID,并定期检查这个守护进程是否还在运行,如果需要的话就重启它。
当然,这个过程需要一些小心(因为一个“过时”的PID会在这个“大家都知道的位置”的文件里存在一段时间,父进程必须考虑到这一点),而且还有一些变种(守护进程可以发出一个“心跳信号”,这样父进程不仅能检测到死掉的守护进程,还能发现那些“卡住了”的守护进程,比如因为死锁而停止发出“心跳信号”[[通过UDP广播或类似方式]]——等等等等),但这就是大致的思路。