php signals exit pcntl

php - ¿Puedo confiar en que se llame a register_shutdown_function() en SIGTERM, si pcntl_signal() está configurado?



signals exit (2)

Además de pilcrows respuesta correcta:

El manejador de señales es necesario para cambiar el comportamiento de la señal (es decir, en lugar de la acción predeterminada). Lo que pase después de eso es irrelevante.

Puede usar el manejador de señales para realizar una limpieza de emergencia y luego llamar a posix_kill(getmypid(), SIGKILL); Para forzar la terminación sin limpieza. Si exit() aquí, normalmente se inicia la secuencia de apagado (es decir, la llamada de todos los destructores, controladores de apagado, etc.).

Cuando dices además , no eres estrictamente correcto. Debe utilizar el controlador de señales en su lugar y, además, puede tener un controlador de apagado. [refiriéndose a su comment ]

También tenga en cuenta que llamar a exit() después de que se haya iniciado la secuencia de apagado abortará la parte actual de la misma (es decir, cuando actualmente se encuentra dentro de un controlador de apagado y se llama a exit() , todos los controladores de apagado posteriores se ignoran, pero por ejemplo, los destructores todavía se llamará). Lo ideal es que tengas algún control contra esto:

register_shutdown_function(function() { $GLOBALS["#__in_shutdown"] = 1; });

y tener un cheque alrededor de la exit() :

if (empty($GLOBALS["#__in_shutdown"])) { exit; }

En caso de que quiera estar realmente a salvo, a menos que alguien le dispare SIGKILL.

Tenga en cuenta que 7.0 o 7.1 no cambiará este comportamiento; todo lo que cambia en 7.1 es declare(ticks=1); Siendo superfluo, el comportamiento exhibido sigue siendo el mismo.

Estoy trabajando en una aplicación que periódicamente se denomina procesos en segundo plano. Uno de estos estaba siendo llamado por cron, pero estoy buscando algo más robusto, así que lo estoy convirtiendo para funcionar bajo Supervisor. (Probablemente se ejecutará durante 10 minutos, tiempo durante el cual puede detectar trabajo por hacer, o inactivo. Una vez que sale, el Supervisor reaparecerá automáticamente en una instancia limpia)

Dado que Supervisor es mejor para garantizar que solo un número específico de instancias de algo se estén ejecutando en paralelo, puedo salir corriendo por más tiempo. Esto significa, sin embargo, que es más probable que mis procesos reciban señales de terminación, ya sea directamente desde el sistema o porque se han detenido a través de Supervisor. Por lo tanto, estoy experimentando con cómo manejar esto en PHP.

Parece que la solución básica es usar pcntl_signal() así:

declare(ticks = 1); pcntl_signal(SIGTERM, ''signalHandler''); pcntl_signal(SIGINT, ''signalHandler''); function signalHandler($signal) { switch($signal) { case SIGTERM: case SIGINT: echo "Exiting now.../n"; exit(); } }

Sin embargo, tengo varios puntos en mi código que podrían hacer con el manejo cuidadoso del apagado. Un enfoque es hacer que un controlador llame a esas diversas cosas, pero requeriría un poco de refactorización, lo que me gustaría evitar. La alternativa es agregar pcntl_signal() cualquier lugar donde lo necesite, pero desafortunadamente parece que solo se puede instalar un controlador a la vez.

Sin embargo, parece que podría ser capaz de usar register_shutdown_function() . Esto no atrapa a ^C u otras señales de terminación por sí mismo, y el manual es bastante claro en este punto:

Las funciones de apagado no se ejecutarán si el proceso se detiene con una señal SIGTERM o SIGKILL

Lo sorprendente es que he encontrado que si uso pcntl_signal() para hacer solo una salida, los manejadores de apagado son llamados. Además, dado que uno puede tener muchos manejadores de apagado, esto resuelve mi problema muy bien: cada clase en mi código que desea manejar la terminación con gracia puede capturar y administrar su propio cierre.

Mi pregunta inicial es, ¿por qué funciona esto? He intentado registrar una función de apagado sin un controlador de señal, y esto no parece ser llamado, como dice el manual. Supongo que el proceso se mantiene vivo en PHP para manejar la señal, lo que hace que se llame a los controladores de apagado.

Además, ¿puedo confiar en este comportamiento, cuando el manual arroja dudas al respecto? Estoy usando PHP 5.5, y todavía no busco actualizar a PHP7. Por lo tanto, me interesaría saber si esto funciona en 5.5 y 5.6, en una variedad de distribuciones.

Por supuesto, si funcionaría (o no) en 7.0 y / o 7.1, también sería interesante. Sin embargo, soy consciente de que las garrapatas se manejarán de manera diferente en 7.1, por lo que hay una mayor probabilidad de que esto tenga un comportamiento diferente. .


Las funciones de cierre de usuario de PHP se llaman durante la terminación del proceso ordinario, de forma análoga a las funciones registradas con atexit en otros lenguajes de programación. Una exit explícita o una exit implícita al final del script es una terminación de proceso ordinaria.

Señal de muerte, sin embargo, es la terminación anormal del proceso. El comportamiento predeterminado para SIGTERM (y el comportamiento obligatorio para SIGKILL) es finalizar el proceso en ejecución inmediatamente, sin ejecutar ningún controlador de limpieza.

Cuando interceptas un SIGTERM con pcntl_signal , estás instalando un comportamiento diferente y te estás dando la oportunidad de experimentar la terminación del proceso normal.

Sí, puedes confiar en este comportamiento. Si bien la entrada principal del manual no es explícita, el resto de la "Nota" que usted cita dice:

[Y] puede usar pcntl_signal() para instalar un controlador para un SIGTERM que usa exit() para finalizar de manera limpia.