5

У меня есть служба, работающая в Ubuntu со следующей конфигурацией:

#/etc/init/my_service.conf

start on (local-filesystems and net-device-up IFACE=eth1)

respawn

exec python -u /opt/XYZ/my_prog.py 2>&1 \
                 | logger -t my_prog.py

При остановке службы с помощью sudo service my_service stop процесс python не прерывается . Уничтожение родительского процесса с помощью kill также не уничтожает процесс Python.

Как полностью остановить службу (т. Е. Все дочерние процессы уничтожены)? В идеале я не хотел бы изменять файл конфигурации выше.

3 ответа3

5

В идеале я не хотел бы изменять файл конфигурации выше.

Tough! Это правильно.

Вам нужно превратить ваш exec в script и прекратить запуск этой программы на python в разветвленном подпроцессе как часть конвейера. Этот ответ ServerFault объясняет, как сделать это во встроенном сценарии оболочки. Я бы внес всего одно изменение в сценарий, приведенный там, в последней строке:

exec python -u /opt/XYZ/my_prog.py 2>&1

В конце концов, нет веской причины не регистрировать стандартную ошибку.

Все более сложные движения, чтобы справиться с разветвлением, от expect daemon до переключения на systemd , упускают момент, когда правильная вещь - это остановить разветвление демона. Если есть что-то хорошее из нынешнего беспорядка, это постоянное подтверждение того, что то, что IBM написала и рекомендовала в 1995 году, было правильным все эти годы.

Привыкайте к идее демонов загрузки цепей . Есть множество наборов инструментов, которые делают такие вещи простыми. Привыкайте к идее не использовать сценарии оболочки тоже. Существует множество наборов инструментов, разработанных специально для этой работы, которые устраняют накладные расходы оболочек (что является известной хорошей идеей в мире Ubuntu).

Например: Команды оболочки в ответе ServerFault могут быть заменены сценарием, который использует инструменты execline Лорана Берко, которые предназначены для того, чтобы делать это без субоболочек и несвязанных FIFO:

#!/command/execlineb -PW
pipeline -w {
    logger -t my_prog.py
} 
fdmove -c 2 1 
python -u /opt/XYZ/my_prog.py

который вы бы тогда просто

exec /foo/this_execlineb_script

С моим набором инструментов nosh это также будет скрипт, содержащий:

#!/usr/local/bin/nosh
pipe 
fdmove -c 2 1 
python -u /opt/XYZ/my_prog.py | logger -t my_prog.py

Или, альтернативно, этот раздел можно было бы указать непосредственно в определении задания Upstart (используя трюк, чтобы избежать метасимволов оболочки, чтобы Upstart не порождал оболочку):

exec /usr/local/bin/exec pipe --separator SPLIT fdmove -c 2 1 python -u /opt/XYZ/my_prog.py SPLIT logger -t my_prog.py

дальнейшее чтение

3

В GNU/Linux обычно нет способа остановить службу и все дочерние процессы, которые она породила, потому что дочерние процессы могут изменить свой PPID (идентификатор родительского процесса). Единственный способ узнать это - отслеживать системные вызовы процессов порождения по мере их появления и вести список этих процессов.

Система инициализации Ubuntu, upstart , этого не делает. Таким образом, ответ на ваш вопрос невозможен - в Ubuntu - без:

  1. Изменение этого скрипта;
  2. Знание точно, какие идентификаторы процесса порождены этим процессом;
  3. Отслеживание этих идентификаторов процессов вручную;
  4. Убив их по отдельности.

Вот почему вы должны запустить дистрибутив Linux, который запускает systemd. Как видите, systemd отслеживает все дочерние процессы и может уничтожить каждый из них с помощью одной команды. Именно так и должно быть системное администрирование GNU/Linux, но поскольку systemd является новым и потому что он "не изобретен здесь" (то есть Canonical не изобретал его), Ubuntu не хочет его использовать.

1

Вы пропустили ожидаемую строфу. В готовящейся кулинарной книге указаны:

Предупреждение

Эта строфа чрезвычайно важна: внимательно прочитайте этот раздел!

Upstart будет отслеживать идентификатор процесса, который, по его мнению, относится к заданию. Если в задании задан раздел экземпляров, Upstart будет отслеживать PID для каждого уникального экземпляра этого задания.

Если вы не укажете ожидаемый раздел, Upstart будет отслеживать жизненный цикл первого PID, который он выполняет в разделах exec или script. Однако большинство сервисов Unix будут "демонизированы", что означает, что они создадут новый процесс (с использованием fork (2)), который является дочерним по отношению к начальному процессу. Часто сервисы "удваиваются", чтобы гарантировать, что они не имеют никакой связи с начальным процессом. (Обратите внимание, что изначально ни одна из служб не будет разветвляться более двух раз, поскольку в этом нет никакой дополнительной выгоды).

В этом случае Upstart должен иметь способ отследить его, поэтому вы можете использовать ожидаемый форк или ожидаемый демон, который позволяет Upstart использовать ptrace (2) для "подсчета вилок".

Чтобы Upstart мог определить окончательный идентификатор процесса для задания, ему необходимо знать, сколько раз этот процесс будет вызывать fork (2). Сама Upstart не может знать ответ на этот вопрос, так как после запуска демона он может затем обработать несколько "рабочих" процессов, которые могут сами разветвляться любое количество раз. Нельзя ожидать, что Upstart будет знать, какой PID является "главным" в этом случае, учитывая, что он не знает, будут ли вообще созданы рабочие процессы, не говоря уже о том, сколько раз или сколько раз процесс будет первоначально разветвляться. Таким образом, необходимо сообщить Upstart, какой PID является "основным" или родительским PID. Это достигается с помощью ожидаемой строфы.

Вам это нужно, потому что труба | вы используете это создание дочерних процессов. Вы можете найти в книге « Расширенное программирование на Linux» краткое введение в то, где сказано, что:

Например, эта команда оболочки заставляет оболочку создавать два дочерних процесса, один для ls и один для меньше:

 $ ls | less

Чего я не знаю, так это того, подразумевает ли это одну или две вилки, так что я бы поэкспериментировал с изменением линии респавна в вашем коде с

 expect fork
 respawn

или же

 expect daemon
 respawn

Я не верю, что это может быть достигнуто только с помощью systemd, хотя мой логотип ясно показывает, что я фанат systemd.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .