Остановка Gunicorn, работающего в сеансе schroot

Я управляю сервером Gunicorn в сеансе schroot через супервизора. Моя проблема заключается в том, что служба останавливается не полностью при остановке с помощью "supervisorctl stop".

Это скрипт (упрощенный), управляющий моим сервером, он запускает gunicorn на переднем плане:

# gunicorn.sh
schroot -c gunicorn -r -- bash -c "gunicorn --workers=1 myapp.wsgi:application" 

Это мой конфиг супервизора для запуска этого скрипта:

[program:gunicorn]
command=/home/test/gunicorn.sh
stderr_logfile=/var/log/gunicorn.err.log
stdout_logfile=/var/log/gunicorn.out.log 

Когда я запускаю сервис через "supervisorctl start", моё дерево процессов выглядит так:

supervisord(7175)---gunicorn.sh(8061)---schroot(8067)---gunicorn(8068)---gunicorn(8073)---{gunicorn}(8078)

Теперь, когда я останавливаю службу с помощью "supervisorctl stop", соответствующий процесс supervisor и его прямой дочерний объект gunicorn.sh завершаются. Но сам процесс schroot продолжает жить и теперь является потомком процесса init:

schroot(8067)---gunicorn(8068)---gunicorn(8073)---{gunicorn}(8078)

Все это поведение, по-видимому, связано как с тем, как работают Шруот и Гантикорн.

Как я могу позволить супервизору правильно остановить процесс, размещенный в schroot?

2 ответа

Решение

Пришлось начинать Gunicorn с exec:

# gunicorn.sh
exec schroot -c gunicorn -r -- bash -c "gunicorn --workers=1 myapp.wsgi:application"

Сегодня я решил точно такую ​​же проблему, но принятое решение не сработало. Та же проблема упоминается, например, здесь.

Для запуска программы с использованием супервизора обычно требуется, чтобы все, что вы выполняете, выполнялось с помощью системного вызова exec() - поскольку он заменяет исходный процесс самим собой, оставляя PID (что важно) для управления супервизором (без отсоединения от терминала, конечно).

Запуск gunicorn в сеансе schroot всегда приводит к двум процессам - schroot, на который ссылается супервизор, и master of gunicorn (рабочие не важны).

Вызов stop в супервизоре просто убивает шрута и заставляет мастера gunicorn мигрировать в init (PID=1), оставляя его фактически запущенным.

Без chroot самый простой способ - просто выполнить exec gunicorn / любой другой /.

Обходной путь, который я нашел, который, кажется, в порядке, таков:

  1. Запустите процесс schroot gunicorn с помощью вспомогательной программы pidproxy (из дистрибутива supervisor, /usr/bin/pidproxy)
  2. Запишите PID процесса gunicorn в файл (обычно путем изменения запуска вашего приложения)
  3. Правильно используйте exec, когда это возможно.

Объявление 1. Используйте pidproxy

[program:xxx]
command = pidproxy /path/to/pid/file /path/to/xxx

Объявление 2. Используйте все средства, чтобы записать pid в файл. Я просто использовал следующий фрагмент кода при запуске приложения:

pid_file = os.path.join(conf.data_dir, "eventaid.pid")
with open(pid_file, "w") as fout:
    fout.write(str(os.getpid()))

Объявление 3. Используйте exec в вашем скрипте /path/to/xxx

# activate venv
. $HOME/.virtualenvs/python3-xxx/bin/activate
# start within schroot
exec schroot -c jessie -- sh -c "exec gunicorn <whatever>"

Теперь отправка SIGTERM/SIGKILL/... изнутри супервизора фактически отправит SIGTERM/SIGKILL/... на pidproxy, который перенаправит сигнал PID воина-убийцы, фактически убив его.

Другие вопросы по тегам