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