procesos de Python deja de responder a SIGTERM / SIGINT después de ser renovadas

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

  •  16-09-2019
  •  | 
  •  

Pregunta

Estoy teniendo un problema extraño con algunos procesos de Python en ejecución un proceso de vigilancia.

El proceso de vigilancia está escrito en Python y es el padre, y tiene una función llamada start_child (nombre) que utiliza subprocess.Popen para abrir el proceso hijo. El objeto Popen se registra de manera que el organismo de control puede controlar el proceso usando poll () y, eventualmente, terminar con terminar () cuando sea necesario. Si el niño muere de forma inesperada, las llamadas de vigilancia start_child (nombre) registra de nuevo y el nuevo objeto Popen.

Hay 7 procesos hijos, todos los cuales son también pitón. Si me quedo ninguno de los niños manualmente, puedo enviar SIGTERM o SIGINT utilizando kill y obtener los resultados que cabe esperar (termina el proceso).

Sin embargo, cuando se ejecuta desde el proceso de vigilancia, el niño solamente terminará después de la primera señal . Cuando el organismo de control reinicia el niño, el nuevo proceso hijo ya no responde a sigterm o SIGINT. No tengo idea de lo que está causando esto.

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)

Así que lo que sucede es watchdog.start () lanza los 7 procesos, y si envío SIGTERM cualquier proceso, se termina, y el hilo de monitor comienza de nuevo. Sin embargo, si a continuación, enviar el nuevo proceso de SIGTERM, lo ignora.

Debería ser capaz de mantener el envío kill -15 a los procesos renovadas una y otra vez. ¿Por qué ignoran que después de ser reiniciado?

¿Fue útil?

Solución

Como se explica aquí: http://blogs.gentoo.org/agaffney/ 2005/03/18 / python_sucks , cuando Python crea un nuevo hilo, que bloquea todas las señales para que el hilo (y para cualquier proceso que genera la rosca).

He arreglado esto utilizando sigprocmask, llamada a través ctypes. Esto puede o no puede ser la forma "correcta" de hacerlo, pero funciona.

En el proceso hijo, 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

Otros consejos

¿No sería mejor para restaurar los manejadores de señales por defecto dentro de Python en lugar de a través de ctypes? En el proceso hijo, utilice el módulo de señal:

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

RuntimeError se eleva al intentar establecer señales tales como SIGKILL que no puede ser capturado.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top