Je cherche quelque chose de mieux que Sudo restart projectname
chaque fois que j'émets un git pull Origin master
, qui tire mes dernières modifications vers un projet Django. Cette commande restart
, je crois, est liée à Upstart, que j'utilise pour démarrer/démarrer mon serveur Gunicorn processus.
Ce redémarrage provoque une brève interruption. Les utilisateurs frappant le serveur Web (nginx) obtiendront un 500, car Gunicorn redémarre toujours. En fait, il semble redémarrer instantanément, mais le chargement des pages prend quelques secondes.
Des idées sur la façon de rendre cela transparent? Idéalement, je voudrais émettre mon git pull
et Gunicorn se recharge automatiquement.
Pour un rechargement gracieux, vous devriez plutôt utiliser la commande reload
d'Upstart, par exemple:
Sudo reload jobname
Selon l'initctl (Upstart) manpage , reload
enverra un signal HUP
au processus:
reload JOB [KEY=VALUE]...
Sends the SIGHUP signal to running process of the named JOB instance.
... qui pour Gunicorn déclenchera un redémarrage gracieux (voir FAQ ).
Vous pouvez dire à Gunicorn de se recharger gracieusement en utilisant le signal HUP
comme ceci:
kill -HUP <pid>
(voir FAQ pour plus de détails)
J'utilise Superviseur pour contrôler mon serveur Gunicorn, ce qui me permet d'utiliser cette façon (légèrement hacky) de recharger Gunicorn après un déploiement:
supervisorctl status gunicorn | sed "s/.*[pid ]\([0-9]\+\)\,.*/\1/" | xargs kill -HUP
Vous pourriez évidemment réaliser quelque chose de similaire avec pidof
, ou ps
.
Ceci est en fait exécuté à partir d'un script Fabric , donc je n'ai même pas besoin de me connecter au serveur.
Pour ceux qui n'utilisent pas supervisord: ce que Rob a dit, cela fonctionne aussi avec ps,
ps aux |grep gunicorn |grep projectname | awk '{ print $2 }' |xargs kill -HUP
Voici le one-liner, si vous exécutez votre service gunicorn avec systemd .
systemctl status gunicorn | sed -n 's/.*Main PID: \(.*\)$/\1/g p' | cut -f1 -d' ' | xargs kill -HUP
Étant donné que les gunicorn docs indiquent que la bonne façon de recharger gracieusement les travailleurs consiste à utiliser kill -HUP <Main PID>
, Où <Main PID>
Est l'ID de processus du processus maître, nous extrayons le maître PID en utilisant systemctl, et exécutez kill -HUP <Main PID>
.
systemctl status gunicorn
où gunicorn
est le nom du service, situé à /etc/systemd/system/
.
Exemple de sortie:
ubuntu@ip-10-4-12-247:~$ systemctl status gunicorn
● gunicorn.service - Gunicorn server for yourproject.com
Loaded: loaded (/etc/systemd/system/gunicorn.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2017-11-04 19:16:24 UTC; 1h 15min ago
Main PID: 10673 (gunicorn)
CGroup: /system.slice/gunicorn.service
├─10673 /home/ubuntu/site/venv/bin/python3 /home/ubuntu/site/venv/bin/gunicorn --workers 3 --bind unix:/tmp/yourproject.socket config.wsgi:application
├─11069 /home/ubuntu/site/venv/bin/python3 /home/ubuntu/site/venv/bin/gunicorn --workers 3 --bind unix:/tmp/yourproject.socket config.wsgi:application
├─11070 /home/ubuntu/site/venv/bin/python3 /home/ubuntu/site/venv/bin/gunicorn --workers 3 --bind unix:/tmp/yourproject.socket config.wsgi:application
└─11071 /home/ubuntu/site/venv/bin/python3 /home/ubuntu/site/venv/bin/gunicorn --workers 3 --bind unix:/tmp/yourproject.socket config.wsgi:application
Nov 04 20:27:04 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:27:04 +0000] [11047] [INFO] Booting worker with pid: 11047
Nov 04 20:27:04 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:27:04 +0000] [11048] [INFO] Booting worker with pid: 11048
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [10673] [INFO] Handling signal: hup
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [10673] [INFO] Hang up: Master
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [11046] [INFO] Worker exiting (pid: 11046)
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [11047] [INFO] Worker exiting (pid: 11047)
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [11048] [INFO] Worker exiting (pid: 11048)
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [11069] [INFO] Booting worker with pid: 11069
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [11070] [INFO] Booting worker with pid: 11070
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [11071] [INFO] Booting worker with pid: 11071
La commande sed fonctionne comme suit: sed 's/<search this>/<replace with this>/g'
s
signifie pour la commande substitute, et g
signifie que la recherche de l'entrée entière globalement.-n
Indique à sed pas d'imprimer chaque ligne (ou en fait, de ne rien imprimer.)p
à la fin indique à sed de imprimer la ligne correspondante..*Main PID: \(.*\)$
, qui est un modèle d'expression régulière, qui se compose des parties suivantes: .*
Correspond à n'importe quel caractère (.
) Zéro ou plusieurs fois (*
). Ensuite, nous recherchons Main PID:
Suivi de tout caractère, répété zéro ou plusieurs fois (.*
). Pour capturer tous les caractères après le texte Main PID:
, Nous mettons le .*
Entre parenthèses, qui sont échappées avec des barres obliques inverses: \(.*\)
. $
Indique la fin de la ligne.\1
, Ce qui signifie le premier jeu de caractères capturé.Exemple de sortie:
ubuntu@ip-10-4-12-247:~$ systemctl status gunicorn | sed -n 's/.*Main PID: \(.*\)$/\1/g p'
10673 (gunicorn)
Dirigez la sortie vers couper . Le cut -f1 -d' '
Signifie que
-d
Détermine le délimiteur, qui est le caractère juste après le -d
. Puisque le délimiteur est l'espace, nous le mettons entre guillemets.-f
Signifie simplement que la découpe est effectuée à l'aide du délimiteur (et non par octets), et -f1
Signifie que nous voulons supprimer le premier élément de la liste.Exemple de sortie:
ubuntu@ip-10-4-12-247:~$ systemctl status gunicorn | sed -n 's/.*Main PID: \(.*\)$/\1/g p' | cut -f1 -d' '
10673
Tuyauter vers xargs signifie simplement exécuter la commande avec les arguments du tuyau sur le côté gauche. Puisque nous ne canalisons que le PID principal vers xargs,
systemctl status gunicorn-Django | sed -n 's/.*Main PID: \(.*\)$/\1/g p' | cut -f1 -d' ' | xargs kill -HUP
est essentiellement la même chose que
echo <Main PID > | xargs kill -HUP
ce qui se traduit par
kill -HUP <Main PID >
Une solution un peu plus robuste consisterait à utiliser cut -f1 -d$'\n'
Ou grep -m1 ""
Devant cut -f1 -d' '
, Pour ne sélectionner que la première ligne de la correspondance. Je ne peux pas imaginer de circonstances, où il y aurait deux correspondances pour le Main PID:
, Cependant.
Ce n'est peut-être pas une réponse directe à la question, mais pour ceux qui cherchent simplement un moyen de redémarrer le serveur Web gunicorn
, vous pouvez utiliser killall gunicorn
puis exécutez une commande pour redémarrer gunicorn. Par exemple:
killall gunicorn
gunicorn --bind 0.0.0.0:80 --reload app:app
Remarque:killall gunicorn
mettra immédiatement fin à tous les processus gunicorn, alors assurez-vous de bien comprendre ce que vous faites.
Nous exécutons Gunicorn sous Supervisor, mais c'est le moyen le plus simple et le plus propre que nous ayons trouvé pour recharger gracieusement Gunicorn quand il est confus:
Sudo pkill -HUP -f gunicorn.*master