Empêcher le double lancement en Python (version améliorée)

Auparavant, j'écrivais une version en utilisant uniquement le fichier de verrouillage, mais c'était impopulaire (?), J'ai donc créé une version en utilisant le fichier pid. Il est facile à utiliser car il est défini comme un décorateur. Faites ce qui suit:

@singleprocess
def main();
    pass

L'opération est la suivante.

  1. Ecrivez le pid dans le fichier pid avant de démarrer le processus principal. Supprimez le fichier pid lorsque le processus est terminé.
  2. Si le processus de pid écrit dans ce fichier pid a déjà la même signature que son propre processus (il est reconnu comme le même programme), il est jugé que le même programme est déjà en cours d'exécution et démarré. ne pas faire.
  3. Comme signature pour juger de l'identité du processus, utilisez la partie de la ligne de commande où le nom du répertoire est exclu du premier paramètre (python) et du second paramètre (nom du fichier python).
  4. Avec cela seul, il y a un problème de cohérence lorsque le timing de lecture et d'écriture du fichier pid se chevauche, donc un mécanisme de verrouillage est inclus lors de la lecture et de l'écriture du fichier pid. Il utilise un troupeau normal.
  5. Par conséquent, si le fichier pid se termine anormalement pendant la lecture ou l'écriture, il peut ne pas démarrer à moins que le fichier pid ne soit supprimé manuellement, mais il n'est pas affecté par l'arrêt anormal du processus principal. Une interruption anormale pendant la lecture et l'écriture du fichier pid ne se produit pas si souvent, ce n'est donc pas un problème en pratique.

Le fichier pid est spécifié pour être placé sous / tmp, et la sécurité n'est pas prise en compte. Pour l'utiliser en production, il peut être nécessaire de modifier l'algorithme getSignature et l'emplacement du fichier pid en fonction de l'application.

def singleprocess(func):
    def basenameWithoutExt(path):
        return os.path.splitext(os.path.basename(path))[0]

    def getSignature(pid):
        processDirectory = '/proc/%d/' % (pid,)
        if os.path.isdir(processDirectory):
            args = open(processDirectory + 'cmdline').read().split("\x00")
            return [os.path.basename(args[0]), os.path.basename(args[1])]
        return None

    @contextmanager
    def filelockingcontext(path):
        open(path, "a").close() #ensure file to exist for locking
        with open(path) as lockFd:
            fcntl.flock(lockFd, fcntl.LOCK_EX)
            yield
            fcntl.flock(lockFd, fcntl.LOCK_UN)

    def wrapper(*args, **kwargs):
        pidFilePath = tempfile.gettempdir() + '/' + basenameWithoutExt(sys.argv[0]) + '.pid'
        with filelockingcontext(pidFilePath):
            runningPid = ""
            with open(pidFilePath) as readFd:
                runningPid = readFd.read()
            if runningPid != "" and getSignature(int(runningPid)) == getSignature(os.getpid()) is not None:
                print("process already exists", file=sys.stderr)
                exit()
            with open(pidFilePath, "w") as writeFd:
                writeFd.write(str(os.getpid()))
        try:
            func(*args, **kwargs)
        finally:
            with filelockingcontext(pidFilePath):
                os.remove(pidFilePath)
    return wrapper

Recommended Posts

Empêcher le double lancement en Python (version améliorée)
Empêcher le double lancement de cron en Python
Empêcher le double lancement de la commande django
lancement de python
Comment vérifier la version d'opencv avec python
Lancer une application Flask dans Python Anywhere
Equation de mouvement à double pendule en python
Quadtree en Python --2
CURL en Python
Métaprogrammation avec Python
Python 3.3 avec Anaconda
Géocodage en python
SendKeys en Python
Mettre python xgboost dans max osx (version llvm)
Méta-analyse en Python
Unittest en Python
Discord en Python
DCI en Python
tri rapide en python
nCr en python
N-Gram en Python
Programmation avec Python
Plink en Python
[Version améliorée] Script pour surveiller le CPU avec Python
Constante en Python
FizzBuzz en Python
Sqlite en Python
Étape AIC en Python
LINE-Bot [0] en Python
CSV en Python
Assemblage inversé avec Python
Réflexion en Python
Version 64 bits de PYTHON2.7
Constante en Python
nCr en Python.
format en python
Scons en Python 3
Puyopuyo en python
python dans virtualenv
PPAP en Python
Quad-tree en Python
Réflexion en Python
Chimie avec Python
Hashable en Python
DirectLiNGAM en Python
LiNGAM en Python
Aplatir en Python
Aplatir en python
"Régression linéaire" et "Version probabiliste de la régression linéaire" en Python "Régression linéaire de Bayes"
Web scraping pour les débutants en Python (1) Version améliorée
[Internal_math version (2)] Décodage de la bibliothèque AtCoder ~ Implémentation en Python ~
Liste triée en Python
AtCoder # 36 quotidien avec Python
Texte de cluster en Python
AtCoder # 2 tous les jours avec Python
Daily AtCoder # 32 en Python
Daily AtCoder # 6 en Python
Modifier les polices en Python