118

Web アプリの一部として Python デーモンを実行しています。デーモンが実行されているかどうかを (Python を使用して) すばやく確認し、実行されていない場合は起動するにはどうすればよいですか?

デーモンのクラッシュを修正するためにそのようにしたいので、スクリプトを手動で実行する必要はありません。スクリプトは呼び出されるとすぐに自動的に実行され、その後は実行され続けます。

スクリプトが実行されているかどうか (python を使用して) 確認するにはどうすればよいですか?

4

20 に答える 20

168

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:
        # The null byte (\0) means the socket is created 
        # in the abstract namespace instead of being created 
        # on the file system itself.
        # Works only in Linux
        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)

これはアトミックであり、プロセスに SIGKILL が送信された場合にロック ファイルが存在するという問題を回避します。

ガベージ コレクション時にソケットが自動的に閉じられることについては、ドキュメントを参照してください。socket.close

于 2011-10-13T17:36:26.663 に答える
107

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 を確実にクリーンアップするようにすることができます。

于 2009-04-25T17:37:56.267 に答える
27

pidライブラリはまさにこれを行うことができます。

from pid import PidFile

with PidFile():
  do_something()

また、pidfile は存在するがプロセスが実行されていない場合も自動的に処理します。

于 2015-10-09T17:55:11.447 に答える
11

もちろん、ダンの例は本来のようには機能しません。

実際、スクリプトがクラッシュしたり、例外が発生したり、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の値をチェックし、二重実行を回避します。

お役に立てば幸いです。

于 2010-11-27T10:41:19.593 に答える
9

UNIX でプロセスを再起動するための非常に優れたパッケージがあります。ビルドと構成に関する優れたチュートリアルがあるのはmonitです。いくつかの調整を行うことで、デーモンを維持する堅固で実証済みのテクノロジを使用できます。

于 2009-04-25T07:16:06.637 に答える
7

無数のオプションがあります。1 つの方法は、そのような呼び出しを実行するシステム コールまたは Python ライブラリを使用することです。もう 1 つは、単純に次のようなプロセスを生成することです。

ps ax | grep processName

出力を解析します。多くの人がこのアプローチを選択しますが、私の見解では必ずしも悪いアプローチではありません。

于 2009-04-25T07:05:50.670 に答える
2

この他のバージョンを試してください

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)
于 2012-10-02T00:09:37.410 に答える
2

私は、デーモンを管理するためのSupervisorの大ファンです。これは Python で書かれているため、Python とやり取りしたり、Python から拡張したりする方法の例がたくさんあります。あなたの目的には、XML-RPC プロセス制御 APIが適切に機能するはずです。

于 2009-04-26T07:36:54.317 に答える
1

独自の PID ファイル ソリューションを開発するのではなく (考えられるよりも微妙でコーナー ケースが多い)、supervisordを見てください。脚本。

于 2014-09-04T10:21:17.737 に答える
0

他の回答は cron ジョブなどに最適ですが、デーモンを実行している場合は、daemontoolsなどで監視する必要があります。

于 2012-06-12T15:31:37.570 に答える
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 を返します。

于 2016-09-22T08:30:38.970 に答える
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
于 2017-04-27T08:09:49.883 に答える
-1

問題を解決するには、次の例を検討してください。

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

このスクリプトは 1 回しか実行できないため、お勧めします。

于 2012-07-12T18:29:35.883 に答える