Python-Daemon não mata seus filhos
-
23-09-2019 - |
Pergunta
Ao usar python-daemon, Estou criando subprocessos gostos:
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())
Quando mato o processo daemônico dos pais (ou seja, um trabalhador) com um Ctrl-C ou Sigterm, etc., as crianças não morrem. Como se mata as crianças?
Meu primeiro pensamento é usar ATEXIT Para matar todos os trabalhadores, gosta de:
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())
No entanto, os filhos dos daemons são coisas complicadas de lidar, e eu seria obrigado por pensamentos e informações sobre como isso deveria ser feito.
Obrigada.
Solução
Suas opções são um pouco limitadas. Se estiver fazendo self.daemon = True
no construtor para o Worker
A classe não resolve seu problema e tentando capturar sinais no pai (ou seja, SIGTERM, SIGINT
) não funciona, você pode ter que tentar a solução oposta - em vez de fazer com que os pais matem os filhos, você pode fazer com que os filhos cometam suicídio quando os pais morrerem.
O primeiro passo é dar o construtor para Worker
a PID
do processo pai (você pode fazer isso com os.getpid()
). Então, em vez de apenas fazer self.queue.get()
No loop do trabalhador, faça algo assim:
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
A solução acima verifica para ver se o pai pai é diferente do que era originalmente (ou seja, se o processo infantil foi adotado por init
ou lauchd
Porque os pais morreram) - veja referência. No entanto, se isso não funcionar por algum motivo, você pode substituí -lo pela seguinte função (adaptada de aqui):
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
Agora, quando o pai morre (por qualquer motivo), as crianças cairão espontaneamente como moscas - exatamente como você queria, seu daemon! :-D
Outras dicas
Você não pode simplesmente armazenar o pid dos pais quando a criança é criada (digamos em self.myppid
) e quando self.myppid
é diferente de getppid()
significa que os pais morreram.
Você também pode usar sinais para evitar a necessidade de verificar se o pai tiver alterado. Não conheço os detalhes do python, mas algo como o que é descrito Aqui (na parte inferior da página) pode funcionar.
Atexit não fará o truque-ele só é executado com terminação não-sinal bem-sucedida-veja a nota perto do topo do documentos. Você precisa configurar o manuseio de sinal através de um de dois meios.
A opção de som mais fácil: defina a bandeira daemon em seus processos de trabalhador, por http://docs.python.org/library/multiprocessing.html#process-and-eceptions
Opção um tanto mais difícil: PEP-3143 Parece sugerir que há uma maneira interna de conectar as necessidades de limpeza do programa em Python-Daemon.