
У меня есть служба, работающая на 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.
Как мне полностью остановить службу (т.е. убить все дочерние процессы)? В идеале я бы хотел не изменять файл конфигурации выше.
решение1
В идеале я бы не хотел изменять указанный выше файл конфигурации.
Круто! Это правильное дело.
Вам нужно изменить свой 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
дальнейшее чтение
- Расс Олбери (18 декабря 2013 г.). Ошибка №727708: upstart предложил политику в Debian. debian-ctte.
- Джонатан де Бойн Поллард (2001).Не используйте fork() для того, чтобы «перевести демон в фоновый режим».". Ошибки, которых следует избегать при разработке программ-демонов Unix. Часто задаваемые ответы.
решение2
В GNU/Linux обычно нет способа остановить службу и все дочерние процессы, которые она породила, потому что дочерние процессы могут изменить свой PPID (идентификатор родительского процесса). Единственный способ узнать это —следсистемные вызовы порождают процессы по мере их создания и ведут список этих процессов.
Система инициализации Ubuntu, upstart
, этого не делает. Так что ответ на ваш вопрос:это невозможно-- в Ubuntu -- без:
- Изменение этого сценария;
- Точно знать, какие идентификаторы процессов порождаются этим процессом;
- Отслеживание идентификаторов этих процессов вручную;
- Убивая их по одному.
Вот почему вам следует использовать дистрибутив Linux, работающий под управлениемсистемд. Как вы видите, systemdотслеживает все дочерние процессыи может убить каждого из них одной командой. Вот как системное администрирование GNU/Linuxдолжно быть, но поскольку systemd является настолько новым и поскольку он «изобретен не здесь» (то есть Canonical не изобрела его), Ubuntu не хочет его использовать.
решение3
Вы пропустилиожидатьстрофа.кулинарная книга upstartопределяет:
Предупреждение
Эта строфа чрезвычайно важна: внимательно прочтите этот раздел!
Upstart будет отслеживать идентификатор процесса, который, по его мнению, принадлежит заданию. Если задание указало строфу экземпляра, Upstart будет отслеживать PID для каждого уникального экземпляра этого задания.
Если вы не укажете строфу expect, Upstart отследит жизненный цикл первого PID, который он выполнит в строфах exec или script. Однако большинство служб Unix будут «демонизировать», то есть они создадут новый процесс (используя fork(2)), который будет потомком исходного процесса. Часто службы будут «дважды разветвляться», чтобы гарантировать, что у них нет никакой связи с исходным процессом. (Обратите внимание, что изначально ни одна служба не будет разветвляться больше двух раз, поскольку в этом нет никакой дополнительной выгоды).
В этом случае у Upstart должен быть способ отслеживать это, поэтому вы можете использовать expect fork или expect daemon, который позволяет Upstart использовать ptrace(2) для «подсчета ветвлений».
Чтобы позволить Upstart определить окончательный идентификатор процесса для задания, ему нужно знать, сколько раз этот процесс вызовет fork(2). Сам Upstart не может знать ответ на этот вопрос, поскольку после запуска демона он может затем разветвить ряд «рабочих» процессов, которые сами могут разветвляться любое количество раз. Нельзя ожидать, что Upstart узнает, какой PID является «главным» в этом случае, учитывая, что он не знает, будут ли вообще созданы рабочие процессы, не говоря уже о том, сколько раз или сколько раз процесс будет разветвляться изначально. Таким образом, необходимо сообщить Upstart, какой PID является «главным» или родительским PID. Это достигается с помощью строфы expect.
Вам это нужно, потому что используемый вами канал |создает дочерние процессы. Вы можете найти в книгеПродвинутое программирование Linuxкраткое введение, где говорится, что:
Например, эта команда оболочки заставляет оболочку создавать два дочерних процесса, один длялси один дляменьше:
$ ls | less
Я не знаю, подразумевает ли это одну или две развилки, поэтому я бы поэкспериментировал с изменением линии.респаунв вашем коде либо с
expect fork
respawn
или
expect daemon
respawn
Я не верю, что это достижимо.толькоссистемд, хотя мой логотип ясно показывает, что я поклонниксистемд.