Python-daemon ne tue pas ses enfants

en utilisant python-daemon , je crée des sous-processus comme:

import multiprocessing

class Worker(multiprocessing.Process):
   def __init__(self, queue):
      self.queue = queue # we wait for things from this in Worker.run()

   ...

q = multiprocessing.Queue()

with daemon.DaemonContext():
    for i in xrange(3):
       Worker(q)

    while True: # let the Workers do their thing
       q.put(_something_we_wait_for())

quand je tue le processus daemonic parent (c.-à-d. pas un Worker) avec un CTRL-C ou SIGTERM, etc., les enfants ne meurent pas. Comment tuer les enfants?

ma première pensée est d'utiliser atexit pour tuer tous les travailleurs, comme:

 with daemon.DaemonContext():
    workers = list()
    for i in xrange(3):
       workers.append(Worker(q))

    @atexit.register
    def kill_the_children():
        for w in workers:
            w.terminate()

    while True: # let the Workers do their thing
       q.put(_something_we_wait_for())

cependant, les enfants de démons sont délicats des choses à gérer, et je serais reconnaissant pour des pensées et des commentaires sur la façon dont cela devrait être fait.

Merci.

20
demandé sur Brian M. Hunt 2010-03-30 06:59:56

3 réponses

vos options sont un peu limitées. Si faire self.daemon = True dans le constructeur pour la classe Worker ne résout pas votre problème et essayer de capter des signaux dans le Parent (i.e., SIGTERM, SIGINT ) ne fonctionne pas, vous pouvez avoir à essayer la solution opposée - au lieu que le parent tue les enfants, vous pouvez avoir les enfants se suicider quand le parent meurt.

la première étape est de donner au constructeur Worker le PID du parent processus (vous pouvez le faire avec os.getpid() ). Puis, au lieu de simplement faire self.queue.get() dans la boucle ouvrière, faire quelque chose comme ceci:

waiting = True
while waiting:
    # see if Parent is at home
    if os.getppid() != self.parentPID:
        # woe is me! My Parent has died!
        sys.exit() # or whatever you want to do to quit the Worker process
    try:
        # I picked the timeout randomly; use what works
        data = self.queue.get(block=False, timeout=0.1)
        waiting = False
    except queue.Queue.Empty:
        continue # try again
# now do stuff with data

la solution ci - dessus vérifie si le DIP du parent est différent de ce qu'il était à l'origine (c'est-à-dire si le processus de l'enfant a été adopté par init ou lauchd parce que le parent est décédé) - voir référence . Toutefois, si cela ne fonctionne pas pour une raison quelconque, vous pouvez le remplacer par le fonction suivante (adaptée de ici ):

def parentIsAlive(self):
    try:
        # try to call Parent
        os.kill(self.parentPID, 0)
    except OSError:
        # *beeep* oh no! The phone's disconnected!
        return False
    else:
        # *ring* Hi mom!
        return True

maintenant, quand le Parent meurt (pour quelque raison que ce soit), les enfants travailleurs tomberont spontanément comme des mouches - comme vous vouliez, vous démon! :-D

31
répondu Daniel G 2017-05-23 12:34:04

ne pouvez-vous pas simplement stocker le pid parent lorsque l'enfant est créé pour la première fois (disons dans self.myppid ) et lorsque self.myppid est différent de getppid() signifie que le parent est mort.

vous pouvez également utiliser des signaux pour éviter la nécessité de continuer à vérifier si le parent a changé. Je ne connais pas les spécificités de python mais quelque chose comme ce qui est décrit ici (au bas de la page) pourrait fonctionner.

3
répondu João Portela 2010-04-09 21:23:02

Atexit de ne pas faire l'affaire-il ne fait que s'exécuter sur le succès de la non-résiliation du signal -- voir la note en haut de la docs . Vous devez configurer la gestion du signal par l'un des deux moyens suivants:

l'option plus facile à sonder: placer le drapeau de démon sur vos processus de travail, par http://docs.python.org/library/multiprocessing.html#process-and-exceptions

option Un peu plus dure: PEP-3143 semble sous-entendre qu'il y a une façon intégrée de répondre aux besoins de nettoyage de programme en python-daemon.

2
répondu Arthur Shipkowski 2010-04-07 16:44:18