processos Python pára de responder a SIGTERM / SIGINT depois de ser reiniciado

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

  •  16-09-2019
  •  | 
  •  

Pergunta

Estou tendo um problema estranho com alguns processos python em execução usando um processo de vigilância.

O processo watchdog é escrito em Python e é o pai, e tem uma função chamada start_child (nome) que usa subprocess.Popen para abrir o processo filho. O objeto Popen é gravado para que o cão de guarda pode monitorar o processo usando poll () e, eventualmente, terminar com terminar () quando necessário. Se a criança morre inesperadamente, as chamadas de vigilância start_child (nome) novamente e registros o novo objeto Popen.

Existem 7 processos filhos, os quais são também python. Se eu executar qualquer um dos filhos manualmente, posso enviar SIGTERM ou SIGINT usando kill e obter os resultados que eu esperava (os fins de processo).

No entanto, quando executado a partir do processo de cão de guarda, a criança só vai terminar após o sinal de PRIMEIRO. Quando o cão de guarda reinicia a criança, o novo processo filho já não responde a SIGTERM ou SIGINT. Eu não tenho idéia o que está causando isso.

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)

Então, o que acontece é watchdog.start () lançamentos de todos os 7 processos, e se eu enviar qualquer SIGTERM processo, ele termina, eo thread de monitor começa novamente. No entanto, se eu, em seguida, enviar a nova SIGTERM processo, ignora-lo.

Eu deveria ser capaz de manter o envio de matar -15 aos processos reiniciado uma e outra vez. Por que eles ignorá-lo depois de ser reiniciado?

Foi útil?

Solução

Como explicado aqui: http://blogs.gentoo.org/agaffney/ 2005/03/18 / python_sucks , quando Python cria uma nova thread, ele bloqueia todos os sinais para esse segmento (e por quaisquer processos que desova de rosca).

Eu reparei isso usando sigprocmask, chamados através ctypes. Isto pode ou não pode ser a maneira "correta" de fazê-lo, mas ela não funciona.

No processo filho, durante __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

Outras dicas

Não seria melhor para restaurar os manipuladores de sinais padrão dentro Python em vez de através ctypes? Em seu processo de criança, use o módulo de sinal:

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

RuntimeError é gerado quando tentando sinais definidos como SIGKILL que não podem ser capturados.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top