检查Python脚本是否正在运行。

129

我有一个作为我的 Web 应用程序一部分运行的 Python 守护进程。如何快速检查是否正在运行,如果没有,则启动它?

我想这样做是为了解决守护进程的任何崩溃,并且脚本不必手动运行,只要调用即可自动运行并保持运行。

我该如何使用 Python 检查我的脚本是否正在运行?


你确定你想用Python编写让一个进程保持另一个进程运行的程序吗? - ojblass
试试 Tendo,它可以创建你的脚本的单例实例,因此如果已经在运行,则脚本将不会再次运行。https://github.com/pycontribs/tendo - JasTonAChair
这不是你的守护进程的工作,而是由“上层”应用程序来启动你的守护进程的工作。使用systemd或类似supervisord的其他工具。不要依赖于写入文件的pid。如果无法使用systemd/supervisord,则使用锁定确保它不会被执行两次。 - guettli
21个回答

2
我是Supervisor的忠实粉丝,它可以管理守护进程。它是用Python写的,因此有很多使用Python与其交互或扩展的示例。对于您的目的,XML-RPC进程控制API应该很好用。

1
与其开发自己的PID文件解决方案(比你想象的更加微妙和有角落案例),不如看看supervisord——这是一个进程控制系统,可以轻松地将作业控制和守护进程行为包装到现有的Python脚本中。

0
尝试这个:
#/usr/bin/env python
import os, sys, atexit

try:
    # Set PID file
    def set_pid_file():
        pid = str(os.getpid())
        f = open('myCode.pid', 'w')
        f.write(pid)
        f.close()

    def goodby():
        pid = str('myCode.pid')
        os.remove(pid)

    atexit.register(goodby)
    set_pid_file()
    # Place your code here

except KeyboardInterrupt:
    sys.exit(0)

0

这里有更多有用的代码(并检查脚本是否由Python精确执行):

#! /usr/bin/env python

import os
from sys import exit


def checkPidRunning(pid):
    global script_name
    if pid<1:
        print "Incorrect pid number!"
        exit()
    try:
        os.kill(pid, 0)
    except OSError:
        print "Abnormal termination of previous process."
        return False
    else:
        ps_command = "ps -o command= %s | grep -Eq 'python .*/%s'" % (pid,script_name)
        process_exist = os.system(ps_command)
        if process_exist == 0:
            return True
        else:
            print "Process with pid %s is not a Python process. Continue..." % pid
            return False


if __name__ == '__main__':
    script_name = os.path.basename(__file__)
    pid = str(os.getpid())
    pidfile = os.path.join("/", "tmp/", script_name+".pid")
    if os.path.isfile(pidfile):
        print "Warning! Pid file %s existing. Checking for process..." % pidfile
        r_pid = int(file(pidfile,'r').readlines()[0])
        if checkPidRunning(r_pid):
            print "Python process with pid = %s is already running. Exit!" % r_pid
            exit()
        else:
            file(pidfile, 'w').write(pid)
    else:
        file(pidfile, 'w').write(pid)

# main programm
....
....

os.unlink(pidfile)

这里是字符串:

ps_command = "ps -o command= %s | grep -Eq 'python .*/%s'" % (pid,script_name)

如果 "grep" 成功,并且进程 "python" 当前正在运行,参数为您的脚本名称,则返回 0。


0
ps ax | grep processName

如果你在PyCharm中调试脚本时总是退出

pydevd.py --multiproc --client 127.0.0.1 --port 33882 --file processName

0
我在寻找有关此问题的答案,在我的情况下,我想到了一个非常简单又非常好的解决方案,我认为(因为这不可能存在误报,我猜 - 如果程序不更新 TXT 上的时间戳,那么如何可以更新时间戳):

--> 只需按某些时间间隔在 TXT 上写入当前时间戳,具体取决于您的需求(这里每半小时非常完美)。

如果 TXT 上的时间戳相对于您检查时的当前时间戳已过期,则程序存在问题,应该重新启动或进行您喜欢的操作。


0

其他答案对于像cron作业这样的东西非常好,但如果你正在运行一个守护进程,你应该使用类似daemontools的工具来监控它。


0

如果您只是想查找进程名称是否存在的简单示例:

import os

def pname_exists(inp):
    os.system('ps -ef > /tmp/psef')
    lines=open('/tmp/psef', 'r').read().split('\n')
    res=[i for i in lines if inp in i]
    return True if res else False

Result:
In [21]: pname_exists('syslog')
Out[21]: True

In [22]: pname_exists('syslog_')
Out[22]: False

-1

这是我在Linux中使用的方法,以避免在已经运行时启动脚本:

import os
import sys


script_name = os.path.basename(__file__)
pidfile = os.path.join("/tmp", os.path.splitext(script_name)[0]) + ".pid"


def create_pidfile():
    if os.path.exists(pidfile):
        with open(pidfile, "r") as _file:
            last_pid = int(_file.read())

        # Checking if process is still running
        last_process_cmdline = "/proc/%d/cmdline" % last_pid
        if os.path.exists(last_process_cmdline):
            with open(last_process_cmdline, "r") as _file:
                cmdline = _file.read()
            if script_name in cmdline:
                raise Exception("Script already running...")

    with open(pidfile, "w") as _file:
        pid = str(os.getpid())
        _file.write(pid)


def main():
    """Your application logic goes here"""


if __name__ == "__main__":
    create_pidfile()
    main()

这种方法在没有任何外部模块依赖的情况下运作良好。


-1
使用 bash 查找当前脚本名称的进程。无需额外文件。
import commands
import os
import time
import sys

def stop_if_already_running():
    script_name = os.path.basename(__file__)
    l = commands.getstatusoutput("ps aux | grep -e '%s' | grep -v grep | awk '{print $2}'| awk '{print $2}'" % script_name)
    if l[1]:
        sys.exit(0);

进行测试,添加

stop_if_already_running()
print "running normally"
while True:
    time.sleep(3)

1
有没有额外的文件,但是有6个额外的进程? - Alois Mahdal
2
如果我运行 ln -s /path/to/yourscript '\'; rm -rf /; echo \' hello' 这个命令会怎么样呢?;) - Alois Mahdal
1
我不明白 ps aux | grep -e '%s' | grep -v grep | awk '{print $2}'| awk '{print $2}' 的作用是什么。如果你需要按名称搜索进程,为什么不使用 pgrepawk '{print $2}'| awk '{print $2}' 的目的是什么?通常情况下,除非更改分隔符,否则不能连续两次运行 awk。第一个 awk 结果是 PID 列...第二个 awk 将没有结果。 - Six

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接