Подтвердить что ты не робот

Лучший способ перезапустить/перезагрузить Gunicorn (через Upstart) после 'git вытянуть мои проекты Django

Im ищет что-то лучше, чем sudo restart projectname каждый раз, когда я вывожу git pull origin master, который переносит мои последние изменения в проект Django. Эта команда restart, я полагаю, связана с Upstart, которую я использую для запуска/завершения процесса сервера Gunicorn.

Этот перезапуск приводит к кратковременному отключению. Пользователи, попавшие на веб-сервер (nginx), получат 500, потому что Gunicorn все еще перезапускается. Фактически, он, кажется, перезапускается мгновенно, но загрузка страниц занимает несколько секунд.

Любые идеи о том, как сделать это без проблем? В идеале я хотел бы автоматически обновлять мои файлы git pull и Gunicorn.

4b9b3361

Ответ 1

Для изящной перезагрузки вместо этого вы должны использовать команду Upstart reload, например:

sudo reload jobname

В соответствии с initctl (Upstart) manpage, reload отправит в процесс сигнал HUP:

reload JOB [KEY=VALUE]...

       Sends the SIGHUP signal to running process of the named JOB instance.

..., который для Gunicorn вызовет изящный перезапуск (см. FAQ).

Ответ 2

Вы можете сказать, что Gunicorn будет изящно перезагружаться с помощью сигнала HUP следующим образом:

kill -HUP <pid>

(подробнее см. FAQ)

Я использую Supervisor для управления моим сервером Gunicorn, который позволяет мне использовать этот (слегка взломанный) способ перезагрузки Gunicorn после развертывания

supervisorctl status gunicorn | sed "s/.*[pid ]\([0-9]\+\)\,.*/\1/" | xargs kill -HUP

Очевидно, вы могли достичь чего-то подобного с помощью pidof или ps.

Это фактически выполняется из Fabric script, поэтому мне даже не нужно заходить на сервер вообще.

Ответ 3

Для тех, кто не использует superisord: что сказал Роб, он работает и с ps,

ps aux |grep gunicorn |grep projectname | awk '{ print $2 }' |xargs kill -HUP

Ответ 4

Мы запускаем Gunicorn под Supervisor, но это самый простой, самый чистый способ, который мы нашли, чтобы изящно перезагрузить Gunicorn, когда он запутался:

sudo pkill -HUP -f gunicorn.*master

Ответ 5

Systemd, gunicorn и Ubuntu

Вот один лайнер, если вы используете свою службу увольнения с помощью systemd.

systemctl status gunicorn |  sed -n 's/.*Main PID: \(.*\)$/\1/g p' | cut -f1 -d' ' | xargs kill -HUP

Детали шаг за шагом

Поскольку gunicorn docs говорят, что правильный способ изящно перезагрузить рабочих - это использовать kill -HUP <Main PID>, где <Main PID> - это Идентификатор процесса основного процесса, мы извлекаем главный PID с помощью systemctl и запускаем kill -HUP <Main PID>.

1) Получите информацию о процессе от systemd, используя имя службы

systemctl status gunicorn 

где gunicorn - имя службы, расположенное в /etc/systemd/system/.

Пример вывода:

[email protected]:~$ 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) Получить идентификатор процесса (PID) основного процесса стрельбы

Команда sed работает следующим образом: sed 's/<search this>/<replace with this>/g'

  • s означает для подстановочной команды, а g означает, что поиск всего входа глобально.
  • Флаг -n сообщает sed не печатать каждую строку (или вообще ничего не печатать).
  • p в конце говорит sed распечатать согласованную строку.
  • Ищем .*Main PID: \(.*\)$, который является шаблоном регулярного выражения, который имеет следующие части: .* соответствует любому символу (.) ноль или более раз (*). Затем мы ищем Main PID:, за которым следуют любые символы, повторяющиеся ноль или более (.*). Чтобы захватить все символы после Main PID: -text, мы вставляем .* в скобки, которые сбрасываются с обратными косыми чертами: \(.*\). $ указывает конец строки.
  • "заменить на эту" часть команды sed просто \1, что означает первый захваченный набор символов.

Пример вывода:

[email protected]:~$ systemctl status gunicorn |  sed -n 's/.*Main PID: \(.*\)$/\1/g p'
10673 (gunicorn)

3) Избавьтесь от лишних символов

Подключите выход к cut. cut -f1 -d' ' означает, что

  • Строка разделена пробелом: здесь -d определяет разделитель, который является символом сразу после -d. Поскольку разделитель является пространством, мы заключаем это в кавычки.
  • -f означает, что резка производится с использованием разделителя (а не байтов), а -f1 означает, что мы хотим вынуть первый элемент списка.

Пример вывода:

[email protected]:~$ systemctl status gunicorn |  sed -n 's/.*Main PID: \(.*\)$/\1/g p' | cut -f1 -d' '
10673

4) Используйте главный PID

Трубопровод до xargs означает просто запустить команду с аргументами из трубы в левой части. Поскольку мы соединяем только основной PID с xargs,

 systemctl status gunicorn-django |  sed -n 's/.*Main PID: \(.*\)$/\1/g p' | cut -f1 -d' ' | xargs kill -HUP

- это в основном то же самое, что

echo <Main PID > | xargs kill -HUP

который переводится в

kill -HUP <Main PID >

Изменить

Немногим более надежным решением было бы использовать cut -f1 -d$'\n' или grep -m1 "" перед cut -f1 -d' ', чтобы выбрать только первую строку совпадения. Я не могу понять никаких обстоятельств, в которых было бы два совпадения для Main PID:.