processus de python cesse de répondre à SIGTERM / SIGINT après avoir été renouvelées

StackOverflow https://stackoverflow.com/questions/1133693

  •  16-09-2019
  •  | 
  •  

Question

Je vais avoir un problème bizarre avec certains processus de python en cours d'exécution en utilisant un processus de surveillance.

Le processus de surveillance est écrit en python et est le parent, et a une fonction appelée start_child (nom) qui utilise subprocess.Popen pour ouvrir le processus enfant. L'objet Popen est enregistré de telle sorte que le chien de garde peut surveiller le processus en utilisant poll () et éventuellement finir avec terminate () en cas de besoin. Si l'enfant meurt de façon inattendue, les appels de surveillance start_child (nom) à nouveau et enregistre le nouvel objet Popen.

Il y a 7 processus enfants, qui sont tous aussi python. Si je lance l'un des enfants manuellement, je peux envoyer SIGTERM ou SIGINT en utilisant kill et obtenir les résultats que j'attends (le processus se termine).

Cependant, lorsqu'il est exécuté à partir du processus de surveillance, l'enfant ne se terminera après le signal FIRST . Lorsque le chien de garde redémarre l'enfant, le nouveau processus enfant ne répond plus à sigterm ou SIGINT. Je ne sais pas ce qui est à l'origine de cette.

watchdog.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)

Alors qu'est-ce qui se passe est watchdog.start () lance tous les 7 processus, et si j'envoie un processus SIGTERM, il se termine, et le fil du moniteur commence à nouveau. Cependant, si j'envoie alors le nouveau SIGTERM de processus, il l'ignore.

Je devrais pouvoir continuer à envoyer kill -15 aux processus renouvelées maintes et maintes fois. Pourquoi ont-ils l'ignorent après avoir redémarré?

Était-ce utile?

La solution

Comme expliqué ici: http://blogs.gentoo.org/agaffney/ 2005/03/18 / python_sucks , lorsque Python crée un nouveau thread, il bloque tous les signaux pour que le fil (et pour tout processus fil fraye).

Je fixe en utilisant ce sigprocmask, appelé par ctypes. Cela peut ou peut ne pas être la « bonne » façon de le faire, mais il fonctionne.

Dans le processus de l'enfant, au cours __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

Autres conseils

Ne serait-il préférable de restaurer les gestionnaires de signaux par défaut au sein de Python plutôt que via ctypes? Dans votre processus d'enfant, utilisez le module de signal:

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

RuntimeError est élevé en essayant de définir des signaux tels que SIGKILL qui ne peut être pris.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top