3

ウォッチドッグ プロセスを使用して実行されている一部の Python プロセスで奇妙な問題が発生しています。

ウォッチドッグ プロセスは Python で記述された親であり、subprocess.Popenを使用して子プロセスを開くstart_child(name)という関数があります。Popen オブジェクトは、ウォッチドッグがpoll()を使用してプロセスを監視し、必要に応じて最終的にterminate()でプロセスを終了できるように記録されます。子が予期せず終了した場合、ウォッチドッグはstart_child(name)を再度呼び出し、新しい Popen オブジェクトを記録します。

7 つの子プロセスがあり、そのすべても Python です。子のいずれかを手動で実行すると、killを使用して SIGTERM または SIGINT を送信し、期待どおりの結果を得ることができます (プロセスは終了します)。

ただし、ウォッチドッグ プロセスから実行すると、子プロセスはFIRSTシグナルの後にのみ終了します。ウォッチドッグが子プロセスを再起動すると、新しい子プロセスは SIGTERM または SIGINT に応答しなくなります。何が原因なのかわかりません。

ウォッチドッグ.py

class watchdog:
    # <snip> various init stuff

    def start(self):
        self.running = true

        kids = ['app1', 'app2', 'app3', 'app4', 'app5', 'app6', 'app7']
        self.processes = {}

        for kid in kids:
            self.start_child(kid)

        self.thread = threading.Thread(target=self._monitor)
        self.thread.start()

        while self.running:
            time.sleep(10)

    def start_child(self, name):
        try:
            proc = subprocess.Popen(name)
            self.processes[name] = proc
        except:
            print "oh no"
        else:
            print "started child ok"

    def _monitor(self):
        while self.running:
            time.sleep(1)
            if self.running:
                for kid, proc in self.processes.iteritems():
                    if proc.poll() is not None: # process ended
                        self.start_child(kid)

したがって、watchdog.start()は 7 つのプロセスすべてを起動し、プロセス SIGTERM を送信するとプロセスが終了し、モニター スレッドが再びプロセスを開始します。ただし、新しいプロセス SIGTERM を送信すると、それは無視されます。

再起動されたプロセスに kill -15 を何度も送信し続けることができるはずです。再起動後に無視されるのはなぜですか?

4

2 に答える 2

5

http://blogs.gentoo.org/agaffney/2005/03/18/python_sucksで説明されているように、Python が新しいスレッドを作成すると、そのスレッド (およびスレッドが生成するすべてのプロセス) のすべてのシグナルがブロックされます。

ctypesを介して呼び出されるsigprocmaskを使用してこれを修正しました。これは「正しい」方法である場合とそうでない場合がありますが、機能します。

子プロセスでは、次の場合__init__:

libc = ctypes.cdll.LoadLibrary("libc.so")
mask = '\x00' * 17 # 16 byte empty mask + null terminator 
libc.sigprocmask(3, mask, None) # '3' on FreeBSD is the value for SIG_SETMASK
于 2009-07-15T23:00:10.763 に答える
0

ctypes 経由ではなく、Python 内でデフォルトのシグナルハンドラーを復元した方がよいのではないでしょうか? 子プロセスで、シグナル モジュールを使用します。

import signal
for sig in range(1, signal.NSIG):
    try:
        signal.signal(sig, signal.SIG_DFL)
    except RuntimeError:
        pass

SIGKILL などのキャッチできないシグナルを設定しようとすると、RuntimeError が発生します。

于 2009-07-16T04:21:35.237 に答える