web-dev-qa-db-fra.com

Une meilleure façon de redémarrer / recharger Gunicorn (via Upstart) après avoir 'git pull'é mes projets Django

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.

54
Flowpoke

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 ).

17
Gary

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.

81
Rob Golding

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
26
thomaspaulb

Systemd, gunicorn et Ubuntu

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

Détails étape par étape

É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>.

1) Obtenez des informations sur le processus de systemd en utilisant le nom du service

systemctl status gunicorn 

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

2) Obtenez l'ID de processus (PID) du processus principal de gunicorn

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.
  • Le drapeau -n Indique à sed pas d'imprimer chaque ligne (ou en fait, de ne rien imprimer.)
  • Le p à la fin indique à sed de imprimer la ligne correspondante.
  • Nous recherchons .*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.
  • La partie "remplacer par ceci" de la commande sed est juste \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)

3) Débarrassez-vous des personnages supplémentaires

Dirigez la sortie vers couper . Le cut -f1 -d' ' Signifie que

  • La chaîne est délimitée par des espaces: ici -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

4) Utilisez le PID principal

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 >

Modifier

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.

7
np8

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.

2

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
2
johntellsall