web-dev-qa-db-fra.com

Vérifiez si python est en cours d'exécution

J'ai un démon python qui s'exécute dans mon application Web/Comment puis-je vérifier rapidement (à l'aide de python) si mon démon est en cours d'exécution et, sinon, le lancer?

Je souhaite le faire de cette manière afin de réparer les plantages du démon. Ainsi, le script ne doit pas nécessairement être exécuté manuellement. Il s'exécutera automatiquement dès qu'il sera appelé, puis continuera à fonctionner.

Comment puis-je vérifier (en utilisant python) si mon script est en cours d'exécution?

89
Josh Hunt

Déposez un fichier pid quelque part (par exemple,/tmp). Ensuite, vous pouvez vérifier si le processus est en cours d'exécution en vérifiant si le PID du fichier existe. N'oubliez pas de supprimer le fichier lorsque vous l'arrêtez proprement et vérifiez-le au démarrage.

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

Ensuite, vous pouvez vérifier si le processus est en cours d'exécution en vérifiant si le contenu de /tmp/mydaemon.pid est un processus existant. Monit (mentionné ci-dessus) peut le faire pour vous, ou vous pouvez écrire un simple script Shell pour le vérifier pour vous en utilisant le code de retour de ps.

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

Pour plus de crédit, vous pouvez utiliser le module atexit pour vous assurer que votre programme nettoie son pidfile en toutes circonstances (mort, exceptions levées, etc.).

88
Dan Udey

Une technique pratique sur un système Linux utilise des sockets de domaine:

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('\0' + process_name)
        print 'I got the lock'
    except socket.error:
        print 'lock exists'
        sys.exit()


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

Il est atomique et évite le problème de fichiers de verrouillage qui traînent si votre processus est envoyé à un SIGKILL

Vous pouvez lisez la documentation de socket.close que les sockets sont automatiquement fermés lorsque les ordures sont collectées.

141
aychedee

La bibliothèque pid peut faire exactement cela.

from pid import PidFile

with PidFile():
  do_something()

Il gérera aussi automatiquement le cas où le pidfile existe mais que le processus n'est pas en cours d'exécution.

17
Decko

Bien entendu, l'exemple de Dan ne fonctionnera pas comme il se doit.

En effet, si le script tombe en panne, lève une exception ou ne nettoie pas le fichier pid, le script sera exécuté plusieurs fois.

Je suggère ce qui suit à partir d'un autre site:

Ceci est pour vérifier s'il existe déjà un fichier de verrouillage

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

Cela fait partie du code où nous mettons un fichier PID dans le fichier de verrouillage

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

Ce code vérifiera la valeur de pid par rapport au processus en cours, évitant une double exécution.

J'espère que cela aidera.

10
Shylock

Il existe de très bons packages pour le redémarrage de processus sous UNIX. Celui qui a un bon tutoriel sur la construction et la configuration est monit . Avec quelques ajustements, vous pouvez avoir une technologie éprouvée et solide pour garder votre démon.

10
ojblass

Il existe une myriade d'options. Une méthode utilise des appels système ou des bibliothèques python qui effectuent de tels appels pour vous. La seconde consiste simplement à générer un processus tel que:

ps ax | grep processName

et analyser la sortie. Beaucoup de gens choisissent cette approche, ce n'est pas nécessairement une mauvaise approche à mon avis.

4
BobbyShaftoe

Essayez cette autre version

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 __== '__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)
3
debuti

Ma solution consiste à vérifier le processus et les arguments de ligne de commande. Testé sous Windows et 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)
3
kabapy

Je suis un grand fan de Superviseur pour la gestion des démons. Il est écrit en Python. Il existe donc de nombreux exemples sur la manière d’interagir avec lui ou de l’extraire de Python. Pour vos besoins, API de contrôle de processus XML-RPC devrait bien fonctionner.

2
Matt Good

Plutôt que de développer votre propre solution de fichier PID (qui comporte plus de subtilités et d’énigmes que vous ne le pensez), jetez un œil à supervisord - c’est un système de contrôle de processus qui facilite le contrôle du travail. et comportements de démon autour d'un script Python existant.

1
Chris Johnson

Je suis tombé sur cette vieille question en cherchant moi-même une solution.

Utilisez 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'])
1
NST

n exemple simple si vous recherchez uniquement un nom de processus existe ou non:

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
0
Tomba

Voici un code plus utile (avec vérifier si exactement python exécute le script):

#! /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 __== '__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)

Voici la chaîne:

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

renvoie 0 si "grep" réussit et que le processus "python" est en cours d'exécution avec le nom de votre script en tant que paramètre.

0
Dmitry Allyanov

Les autres réponses sont utiles pour des tâches telles que les tâches cron, mais si vous utilisez un démon, vous devez le surveiller avec quelque chose comme daemontools .

0
bobpoekert

essaye ça:

#/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
MrRolling
ps ax | grep processName

si votre script de débogage dans pycharm quitte toujours

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