如果Python脚本被杀死或死亡,如何自动重启


31

我像这样在我的Ubuntu机器(12.04)中在后台运行Python脚本-

nohup python testing.py > test.out &

现在,在某些情况下,我的上面Python script可能由于某种原因而死亡。

因此,我正在考虑使用某种cron agentin bash shell脚本,如果由于某种原因被杀死,它可以自动重新启动上述Python脚本。

这可能吗?如果是,那么解决此类问题的最佳方法是什么?

更新:

testing.conf像这样创建文件后-

chdir /tekooz
exec python testing.py
respawn

我在sudo命令下运行以启动它,但是我看不到使用ps ax在后面运行该进程?

root@bx13:/bezook# sudo start testing
testing start/running, process 27794
root@bx13:/bezook# ps ax | grep testing.py
27806 pts/3    S+     0:00 grep --color=auto testing.py

知道为什么px ax没有显示任何内容吗?以及如何检查我的程序是否正在运行?

这是我的python脚本-

#!/usr/bin/python
while True:
    print "Hello World"
    time.sleep(5)

Answers:


24

在Ubuntu(直到14.04、16.04及更高版本使用systemd)上,可以使用upstart这样做,这比执行cron作业要好。您放入配置设置,/etc/init并确保指定重生

它可能是最小文件/etc/init/testing.conf(编辑为root):

chdir /your/base/directory
exec python testing.py
respawn

您可以使用/your/base/directory/testing.py以下命令进行测试:

from __future__ import print_function

import time

with open('/var/tmp/testing.log', 'a') as fp:
    print(time.time(), 'done', file=fp)
    time.sleep(3)

然后开始:

sudo start testing

并跟随发生的事情(在另一个窗口中):

tail -f /var/tmp/testing.log

然后停止:

sudo stop testing

您还可以添加[start on][2]以使命令在系统引导时启动。


如果使用cron作业,则需要实现或找到一些代码来进行可靠的PID文件处理。您想让您的service / script / daemon创建一个PID文件(通常位于/ var / run下),并使其启动代码检查文件内容是否陈旧(被杀死的进程留下)。令人难以置信的是,这种代码很难编写出没有种族和极端情况的代码。stackoverflow.com/questions/788411/...
吉姆·丹尼斯

@Zelda:感谢您的建议。.我是Linux / Unix世界的新手。.我应该在/etc/init文件中进行哪种类型的更改?如果您可以提供一步一步地指导我,那么我就可以学到东西,做正确的事..
阿森纳

@Webby我使答案更加完整。如果您不想打开文件进行输出并重写打印语句,则可以sys.stdout = open(file_name, 'w')在开始时执行类似的操作。
Zelda 2014年

谢谢塞尔达。感谢您的帮助。.我用一些详细信息更新了问题..我试图这样做,以查看我的testing.py是否正在运行..它没有显示我是否正在运行px ax | grep testing.py....它什么也没回报?知道为什么吗?
阿森纳2014年

您应该将整个内容放在try / except子句中,并将生成的异常以及程序退出的内容写入日志文件。也许print语句无法正常工作,因为它无法写入stdout。
Zelda 2014年

20

您也可以采用更面向外壳的方法。有你cron看看你的脚本,然后重新启动它,如果它死了。

  1. 通过运行创建新的crontab crontab -e。这将打开您喜欢的文本编辑器的窗口。

  2. 将此行添加到刚打开的文件中

    */5 * * * * pgrep -f testing.py || nohup python /home/you/scripts/testing.py > test.out
  3. 保存文件并退出编辑器。

您刚刚创建了一个新crontab的脚本,它将每5分钟运行一次,并启动您的脚本,除非该脚本已在运行。请参阅此处,获得有关的不错的小教程cron。Ubuntu官方文档上cron位置

正在运行的实际命令是在正在pgrep运行的进程中搜索命令行中给定的字符串。pgrep foo将搜索名为的程序foo并返回其进程标识符pgrep -f使它搜索用于启动程序的整个命令行,而不仅搜索程序名(因为这是python脚本,所以很有用)。

||符号表示“如果先前的命令失败,请执行此操作”。因此,如果您的脚本未运行,则pgrep它将失败,因为它将找不到任何内容,并且您的脚本将被启动。


谢谢..但是我是Linux和UNIX的新手,所以不知道crontab在哪里?这是我的ubuntu机器中的某个文件吗?
阿森纳2014年

@Webby看到更新的答案。
terdon

谢谢terdon ..我可以crontab -e从我的python脚本所在的目录中运行此命令。
阿森纳2014年

1
@Webby您可以从任何位置运行它。cron是调度守护程序,它是在后台运行的服务。如果您的python脚本不在您的Python脚本中$PATH(如果您无法从任何地方启动它,但需要在其目录中),请使用该脚本的完整路径,如我的最新答案。
terdon

谢谢。现在它变得有意义了。我刚刚创建了一个新的crontab,并通过添加同一行但只编辑了1分钟来编辑了文件。 crontab文件,它应在1分钟后自动启动testing.py吗?然后每隔1分钟继续检查python脚本是否正在运行?如果是,在保存crontab -e文件后,我做了ps ax | grep testing.py,我看不到任何流程吗?
阿森纳2014年

6

您可以让测试程序使用命令行选项重定向输出,然后使用简单的python脚本无限期地重新启动程序:

import subprocess

while True:
    try:
        print subprocess.check_output(['python', 'testing.py'])
    except KeyboardInterrupt:
        break

您可以将该程序放在后台,一旦要停止,就将其拉到前台并杀死它。


6

您实际上不应该将其用于生产,但是您可以:

#!/bin/sh

while true; do
  nohup python testing.py >> test.out
done &

如果由于某种原因退出python进程,则shell循环将继续并重新启动它,并.out根据需要将其追加到文件中。几乎没有开销,并且只需要很少的时间来设置。


6

在UNIX / Linux下,有许多方法可以监视和重新生成进程。如果使用的是旧的SysV初始化系统,则最旧的文件之一是/ etc / inittab中的“ respawn”条目。另一种方法是使用DJ Bernstein的daemontools软件包中的超级用户守护程序。其他选项是在Ubuntu upstart ...或systemd或其他版本中使用功能。

但是您可以在Pardus的Python代码中找到替代方法init,尤其是mudur守护程序。

如果决定进行cron作业(和PID文件处理),则可以考虑阅读此PEP 3143,并可能使用其参考实现。

正如我在其他评论中提到的那样,强大的PID文件处理非常棘手。容易出现种族和极端情况。如果您的PID文件有可能最终被存储在NFS或其他网络文件系统上,则将变得更加棘手(某些原子性保证了您在适当的本地 UNIX / Linux文件系统上使用文件处理语义时所获得的东西在NFS的某些版本和实现上就消失了,例如)。同样,在UNIX下围绕文件锁定的语义可能很棘手。(例如,当持有SIG flockfcntlLOCK的进程被SIGKILL杀死时,它会在目标OS中迅速释放吗?)。


3

您还可以在ps-watcher中使用monitProcess监视

Monit是一个开源实用程序,用于管理和监视UNIX系统上的进程,程序,文件,目录和文件系统。Monit会进行自动维护和修复,并可以在错误情况下执行有意义的因果操作。

这是您的情况的示例:

check process myprocessname
        matching "myprocessname"
        start program = "nohup /usr/bin/python /path/testing.py > /tmp/test.out &"
        stop program = "/usr/bin/killall myprocessname"

看一下monit示例


1

你需要一个主管,你可以使用主管。它是基于python的主管,因此如果需要,可以轻松进行修改。

控制使用.ini文件语法的文件。


0

Terdon的回答对我没有用,因为 pgrep -f testing.py从来没有“失败”。它会捕获cron作业的pid(由于-f选项)。但是,如果没有-f选项,则pgrep不会找到testing.py,因为没有名为test.py的进程。

我对此的解决方案是更改

pgrep -f testing.py

pgrep -f testing.py | pgrep python

这意味着完整的crontab作业将是:

*/5 * * * * pgrep -f testing.py | pgrep python || nohup python /home/you/scripts/testing.py > test.out

0

就我而言,作为一种快速修复,我希望在程序退出并出现错误或被杀死时保持程序运行。另一方面,我想在程序正确终止时停止执行(返回码= 0)

我已经在Bash上进行了测试。它应该可以在其他外壳中正常工作

#!/bin/sh

echo ""
echo "Use: $0 ./instagram.py"
echo ""

echo "Executing $1 ..."

EXIT_CODE=1
(while [ $EXIT_CODE -gt 0 ]; do
    $1
    # loops on error code: greater-than 0
    EXIT_CODE=$?
done)

0

对于terdon的答案,pgrep -f testing.py将永远不会根据此处的注释返回false :

我认为问题在于cron产生了一个shell来运行您的命令,并且由于使用了-f,因此pgrep会匹配该shell的参数

对于马特(Matt)的答案,它pgrep -f testing.py是无用的,因为它可以pgrep python匹配任何正在运行的Python脚本。因此,如果有两个Python脚本cronjob,则第二个cronjob将永远不会运行。

然后我pgrep -f testing.py在这里的评论中找到了要解决的解决方案:https : //askubuntu.com/questions/1014559/running-pgrep-in-a-crontab?noredirect=1&lq=1

我的计划运行两个Python脚本:

* * * * * pgrep -f '^/usr/bin/python36 /home/ec2-user/myscript1\.py' || nohup /usr/bin/python36 /home/ec2-user/myscript1.py

0 * * * * pgrep -f '^/usr/bin/python36 /home/ec2-user/myscript2\.py' || nohup /usr/bin/python36 /home/ec2-user/myscript2.py
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.