Arrêt gracieux de Nginx / PHP FPM (SIGQUIT): pas si gracieux

En cours d’exécution nginx 1.9. * / PHP 7.0. * (Mais exactement le même comportement en 5.6. * Aussi)

Tenter d’arrêter correctement un combo PHP-FPM / nginx pour l’arrêt du noeud pendant la maintenance. Pour ce faire, je vais envoyer le SIGQUIT à php-fpm, ce qui devrait permettre un arrêt en douceur.

Pour tester cela, j’ai fait un script idiot

<?php sleep(5); echo 'done'; 

Testé localement avec la boucle suivante

 curl -I xxxx:8080 

Qui produit normalement la sortie:

 HTTP/1.1 200 OK Server: nginx Date: Tue, 12 Apr 2016 04:48:00 GMT Content-Type: text/html; charset=UTF-8 Connection: close 

Désireux: au milieu d’une demande en vol, lorsqu’un arrêt normal est demandé, les requêtes en cours doivent se terminer, mais toute demande supplémentaire doit échouer.

Malheureusement, lorsque j’essaie de déclencher ce comportement, en envoyant un SIGQUIT ( http://manpages.ubuntu.com/manpages/precise/man8/php5-fpm.8.html ) au processus principal de PHP-FPM:

 kill -s SIGQUIT $FPMPID 

La connexion est immédiatement interrompue, résultant en un ngnix 502

 HTTP/1.1 502 Bad Gateway Server: nginx Date: Tue, 12 Apr 2016 04:48:07 GMT Content-Type: text/html Content-Length: 166 Connection: close 

Aucun conseil? J’aimerais rendre ce morceau du système aussi transparent que possible. Merci!

Après avoir lutté contre cette situation pendant un moment, je crois avoir trouvé le paramètre de configuration magique pour que les processus enfants finissent de gérer les requêtes avant de mourir.

http://php.net/manual/en/install.fpm.configuration.php#process-control-timeout

process_control_timeout

Délai pour que les processus enfants attendent une réaction sur les signaux du maître

Fondamentalement, en définissant cela à quelque chose comme 10s , le processus enfant attendra si longtemps, tout en gérant les demandes existantes avant de quitter.

Malheureusement, il semble que le processus maître php-fpm immédiatement, donc, inspiré par le code ici , j’ai écrit un script wrapper:

 #!/bin/bash PHP_FPM_PID='/php-fpm.pid' wait_for_pid () { try=0 while test $try -lt 35 ; do if [ ! -f "$1" ] ; then try='' break fi echo -n . try=`expr $try + 1` sleep 1 done } function clean_up { echo "Killing $(cat $PHP_FPM_PID)" kill -QUIT `cat $PHP_FPM_PID` wait_for_pid $PHP_FPM_PID echo "Done!" exit 0 } trap clean_up EXIT nohup php-fpm --daemonize --pid $PHP_FPM_PID 2>&1 & while true; do sleep 1; done # ^ do nothing forever 

qui attend 35 secondes ou jusqu’à ce que ce fichier pid ait été supprimé (probablement par l’un des processus enfants? Je ne sais toujours pas comment il est supprimé).

Quoi qu’il en soit, ce script de wrapper fonctionne bien comme CMD pour notre conteneur docker php-fpm que nous exécutons avec Kubernetes.