Проверьте, запущен ли скрипт python

У меня есть демон python, работающий как часть моего веб-приложения/ как я могу быстро проверить (используя python), работает ли мой демон, а если нет, запустите его?

Я хочу сделать это таким образом, чтобы исправить любые сбои демона, и поэтому сценарий не должен запускаться вручную, он будет автоматически запускаться, как только он будет вызван, а затем оставаться запущенным.

Как я могу проверить (используя python), работает ли мой скрипт?

19 ответов


поместите где-нибудь pidfile (например, /tmp). Затем вы можете проверить, запущен ли процесс, проверив, существует ли PID в файле. Не забудьте удалить файл при чистом завершении работы и проверить его при запуске.

#/usr/bin/env python

import os
import sys

pid = str(os.getpid())
pidfile = "/tmp/mydaemon.pid"

if os.path.isfile(pidfile):
    print "%s already exists, exiting" % pidfile
    sys.exit()
file(pidfile, 'w').write(pid)
try:
    # Do some actual work here
finally:
    os.unlink(pidfile)

затем вы можете проверить, запущен ли процесс, проверив содержимое /tmp / mydaemon.pid-это существующий процесс. Monit (упомянутый выше) может сделать это за вас, или вы можете написать простой скрипт оболочки для проверки это для вас, используя код возврата из ps.

ps up `cat /tmp/mydaemon.pid ` >/dev/null && echo "Running" || echo "Not running"

для дополнительного кредита вы можете использовать модуль atexit, чтобы убедиться, что ваша программа очищает свой pidfile при любых обстоятельствах (когда убит, исключения подняты и т. д.).


метод, который удобен в системе Linux, использует доменные сокеты:

import socket
import sys
import time

def get_lock(process_name):
    # Without holding a reference to our socket somewhere it gets garbage
    # collected when the function exits
    get_lock._lock_socket = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)

    try:
        get_lock._lock_socket.bind('' + process_name)
        print 'I got the lock'
    except socket.error:
        print 'lock exists'
        sys.exit()


get_lock('running_test')
while True:
    time.sleep(3)

это атомарный и позволяет избежать проблемы блокировки файлов, лежащих вокруг, если ваш процесс получает отправлен SIGKILL

Вы можете прочитайте в документации для socket.close что сокеты автоматически закрываются при сборе мусора.


на pid библиотека может сделать точно это.

from pid import PidFile

with PidFile():
  do_something()

Он также автоматически обрабатывает случай, когда pidfile существует, но процесс не выполняется.


есть очень хорошие пакеты для перезапуска процессов в UNIX. Тот, у которого есть отличный учебник по строительству и настройке, это монит. С некоторыми настройками вы можете иметь прочную проверенную технологию, поддерживающую ваш демон.


конечно, пример от Dan не будет работать так, как должно быть.

действительно, если сценарий аварийно завершает работу, создает исключение или не очищает PID-файл, сценарий будет запущен несколько раз.

Я предлагаю следующее на основе другого веб-сайта:

это проверить, существует ли уже файл блокировки

\#/usr/bin/env python
import os
import sys
if os.access(os.path.expanduser("~/.lockfile.vestibular.lock"), os.F_OK):
        #if the lockfile is already there then check the PID number
        #in the lock file
        pidfile = open(os.path.expanduser("~/.lockfile.vestibular.lock"), "r")
        pidfile.seek(0)
        old_pid = pidfile.readline()
        # Now we check the PID from lock file matches to the current
        # process PID
        if os.path.exists("/proc/%s" % old_pid):
                print "You already have an instance of the program running"
                print "It is running as process %s," % old_pid
                sys.exit(1)
        else:
                print "File is there but the program is not running"
                print "Removing lock file for the: %s as it can be there because of the program last time it was run" % old_pid
                os.remove(os.path.expanduser("~/.lockfile.vestibular.lock"))

это часть кода, где мы помещаем PID-файл в файл блокировки

pidfile = open(os.path.expanduser("~/.lockfile.vestibular.lock"), "w")
pidfile.write("%s" % os.getpid())
pidfile.close()

этот код проверит значение pid по сравнению с существующим запущенным процессом., избегая двойного исполнения.

Я надеюсь, что это поможет.


существует множество вариантов. Одним из методов является использование системных вызовов или библиотек python, которые выполняют такие вызовы для вас. Другой-просто породить такой процесс, как:

ps ax | grep processName

и парсить вывод. Многие люди выбирают такой подход, это не обязательно плохой подход, на мой взгляд.


попробуйте эту другую версию

def checkPidRunning(pid):        
    '''Check For the existence of a unix pid.
    '''
    try:
        os.kill(pid, 0)
    except OSError:
        return False
    else:
        return True

# Entry point
if __name__ == '__main__':
    pid = str(os.getpid())
    pidfile = os.path.join("/", "tmp", __program__+".pid")

    if os.path.isfile(pidfile) and checkPidRunning(int(file(pidfile,'r').readlines()[0])):
            print "%s already exists, exiting" % pidfile
            sys.exit()
    else:
        file(pidfile, 'w').write(pid)

    # Do some actual work here
    main()

    os.unlink(pidfile)

Я большой поклонник руководитель для управления демонами. Он написан на Python, поэтому есть много примеров того, как взаимодействовать или расширять его с Python. Для ваших целей XML-RPC API управления процессами должны работать хорошо.


наткнулся на этот старый вопрос, ища решение сам.

использовать psutil:

import psutil
import sys
from subprocess import Popen

for process in psutil.process_iter():
    if process.cmdline() == ['python', 'your_script.py']:
        sys.exit('Process found: exiting.')

print('Process not found: starting it.')
Popen(['python', 'your_script.py'])

мое решение-проверить аргументы процесса и командной строки Протестировано на windows и ubuntu linux

import psutil
import os

def is_running(script):
    for q in psutil.process_iter():
        if q.name().startswith('python'):
            if len(q.cmdline())>1 and script in q.cmdline()[1] and q.pid !=os.getpid():
                print("'{}' Process is already running".format(script))
                return True

    return False


if not is_running("test.py"):
    n = input("What is Your Name? ")
    print ("Hello " + n)

другие ответы отлично подходят для таких вещей, как задания cron, но если вы используете демона, вы должны контролировать его с помощью чего-то вроде сайтов.


ps ax | grep processName

Если yor debug script в pycharm всегда выходит

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

вместо того, чтобы разрабатывать собственное решение PID-файла (которое имеет больше тонкостей и угловых случаев, чем вы могли бы подумать), посмотрите на supervisord -- это система управления процессом, которая позволяет легко обернуть управление заданиями и поведение демона вокруг существующего скрипта Python.


попробуйте это:

#/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)

вот более полезный код (с проверкой, точно ли 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)

возвращает 0, если " grep "успешен, и процесс" python " в настоящее время выполняется с именем вашего скрипта в качестве параметра .


простой пример, если вы ищете только имя процесса существует или нет:

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

рассмотрим следующий пример, чтобы решить вашу проблему:

#!/usr/bin/python
# -*- coding: latin-1 -*-

import os, sys, time, signal

def termination_handler (signum,frame):
    global running
    global pidfile
    print 'You have requested to terminate the application...'
    sys.stdout.flush()
    running = 0
    os.unlink(pidfile)

running = 1
signal.signal(signal.SIGINT,termination_handler)

pid = str(os.getpid())
pidfile = '/tmp/'+os.path.basename(__file__).split('.')[0]+'.pid'

if os.path.isfile(pidfile):
    print "%s already exists, exiting" % pidfile
    sys.exit()
else:
    file(pidfile, 'w').write(pid)

# Do some actual work here

while running:
  time.sleep(10)

Я предлагаю этот скрипт, потому что он может быть выполнен только один раз.


использование 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 }'| awk '{print }'" % script_name)
    if l[1]:
        sys.exit(0);

чтобы проверить, добавьте

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

Это то, что я использую в 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()

этот подход работает хорошо без какой-либо зависимости от внешнего модуля.