Поймать сигналы, отправленные runit (sv stop <id>)

У меня есть программа на Python, которая выполняет несколько рабочих процессов. Поскольку это должно быть обработано правильно, чтобы избежать потерянных процессов, я реализовал обработчик сигналов для отключения всех рабочих процессов.

Программа запускается примерно так:

  1. Запуск процесса пула (запускается X количество рабочих)
  2. Регистрировать обработчики сигналов (signal.signal(signal.SIGTERM, my_signal_handler)). Я также добавляю еще один обработчик сигнала для SIGINT с тем же обработчиком.
  3. Запустите отдельный бэкэнд опроса потоков (базу данных) и добавьте задачи в пул процессов.
  4. В основном потоке опросить пул процессов для получения результатов (есть результат multiprocessing.Queue что отдельные работники добавляют результаты).

Идея состоит в том, что два отдельных потока, начатые в 3 и 4, поддерживают выполнение задач через механизм.

Если я начну это вручную и позвоню kill -15 <pid> или же kill -2 <pid> он корректно закрывает все, ждет процессов join(), Читая из документации, runit отправляет TERM к процессу, а затем CONT, Однако, запустив это под runit, он просто показывает стандарт ok: down: <my_program>: 1s, normally up, но процесс все еще работает в фоновом режиме (даже основной процесс, он НЕ УТВЕРЖДЕН).

Если я потом выйду и вручную убью процесс, я смогу увидеть в файле журнала, что он корректно завершает работу. Что я делаю неправильно? Кажется, что runit ТОЛЬКО убивает трехстрочный скрипт, который я создал для активации virtualenv, но оставляет фактический процесс python позади.

Даже если я запускаю скрипт "run" напрямую, я могу запустить kill или Ctrl+C (так же, как SIGINT) и он выключается правильно.

1 ответ

Решение

Итак, после некоторого обширного тестирования я понял это.

Runit отправит сигнал уничтожения run скрипт, который не распространяет его по умолчанию. Вам нужно убедиться, что вы звоните exec python yourscript.py в конце. Точно так же, если ваш run скрипт вызывает другой скрипт оболочки (т.е. тот, который активирует ваш virtualenv или аналогичный), он должен делать это с exec также.

Образцы:

run:

#!/bin/sh
umask 002
2>&1
exec chpst -uanalytics cliscript router

cliscript:

#!/bin/sh

# Resolve script path, assuming that the script resides in $(ABSPATH)/bin
SCRIPTPATH="$0"
if [ -h "$SCRIPTPATH" ]; then
    SCRIPTPATH=$(readlink -e "$0")
fi
ABSPATH=$(dirname "$(cd "$(dirname "$SCRIPTPATH")"; pwd -L)")

# Load the virtual environment
source "$ABSPATH/venv/bin/activate"

# Set up environment
export PYTHONUNBUFFERED=1

exec python "$ABSPATH/bin/processing-cli.py" $@

Принять к сведению exec вызывается, когда мы "передаем" управление следующему скрипту или самому питону.

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