Почему «процесс не должен разветвляться» для служб простого типа в systemd?
Я хочу написать свои собственные systemd
файлы модулей для управления действительно долгими командами 1 (в порядке часов). При просмотре статьи ArchWiki о systemd в ней говорится следующее относительно выбора типа запуска:
Type=simple
(по умолчанию): systemd считает, что служба запускается немедленно. Процесс не должен развиваться . Не используйте этот тип, если для этого сервиса необходимо заказать другие услуги, если он не активирован сокетом.
Почему процесс вообще не должен развиваться? Имеется в виду разветвление в стиле процесса вызова демона (родительские вилки, затем выходы) или любой вид разветвления?
1 Мне не нужен tmux / screen, потому что мне нужен более элегантный способ проверки статуса и перезапуска службы, не прибегая к помощи tmux send-keys
.
Ответы
Сервису разрешено вызывать fork
системный вызов. Systemd не предотвратит этого и даже не заметит, если это произойдет. Это предложение конкретно относится к практике разветвления в начале демона, чтобы изолировать демона от его родительского процесса. «Процесс не должен разветвляться [и выходить из родительского при запуске службы в дочернем процессе]».
На странице руководства это объясняется более подробно и с формулировкой, которая не приводит к этой конкретной путанице.
Многие программы, которые предназначены для использования в качестве демонов, имеют режим (часто режим по умолчанию), в котором при запуске они изолируют себя от своих родителей. Демон запускается, вызывает fork()
и родительский элемент завершает работу. Дочерний процесс вызывает, setsid()
чтобы он работал в своей собственной группе процессов и сеансе, и запускает службу. Цель состоит в том, что если демон вызывается из командной строки оболочки, демон не получит никакого сигнала от ядра или от оболочки, даже если что-то произойдет с терминалом, например, закрытие терминала (в этом случае оболочка отправляет SIGHUP ко всем группам процессов, о которых он знает). Это также приводит к тому, что процесс обслуживания принимается init, который пожинает его при выходе, избегая зомби, если демон был запущен чем-то, что не wait()
для него (этого не произошло бы, если бы демон был запущен оболочкой ).
Когда демон запускается процессом мониторинга, таким как systemd, разветвление контрпродуктивно. Предполагается, что процесс мониторинга перезапустит службу в случае сбоя, поэтому ему нужно знать, завершается ли служба, а это сложно, если служба не является прямым потомком процесса мониторинга. Предполагается, что процесс мониторинга никогда не прекратится, и у него нет управляющего терминала, поэтому нет никаких опасений по поводу нежелательных сигналов или жатвы. Таким образом, нет причин, по которым процесс обслуживания не является дочерним по отношению к монитору, и для этого есть веская причина.
Игнорируйте эту вики-страницу Arch.
Что касается Type
настройки, то здесь все довольно не так . simple
Более того, это не ограничивается его описанием . То, о чем он говорит forking
, тоже неверно.
Правильные рекомендации для такого рода вещей существуют на десятилетия дольше, чем существовала сама systemd, и восходят, по крайней мере, к началу 1990-х годов. Как я заметил наhttps://unix.stackexchange.com/a/476608/5132, в systemd doco есть недавно появившаяся версия рекомендаций для демонов, которая в значительной степени повторяет то, что пользователи daemontools, IBM, люди используют inittab
и… ну… я говорил десятилетиями. (Этот ответ уже часто давали, когда я писал его как таковой в 2001 году.)
Повторять:
Если в вашей программе есть некий механизм «демонизации», который, в частности, разветвляет дочерний процесс и завершает родительский процесс, выключите его и не используйте . Благодаря daemontools et al. там, где это было требованием в течение долгого времени, многие программы за последние более 20 лет научились не иметь таких механизмов, а другие просто не по умолчанию изначально «демонизируют», поэтому их можно использовать в их режимы работы по умолчанию.
Подсистемы управления сервисами запускают сервисные процессы уже в контексте демона . Эти процессы не нужно «демонизировать». (Действительно, во многих современных операционных системах ошибочно полагать, что программы могут даже «демонизировать» контекст сеанса входа в систему, в чем и заключается «демонизация».) У них уже есть значения среды и дескрипторы открытых файлов, ассигновать DAEMON контекста, и некоторые вещи , сделанные с помощью «dæmonization» фактически расстроить некоторых из обычных вещей, которые регулярно делается с Демонов (например , захватив их стандартные выходы / ошибки в журнал) менеджерами услуг.
Предпочтительно Type=simple
с ранним открытием сокета (когда служба управления открывает серверные сокеты и передает их как уже открытые файловые дескрипторы служебной программе) или Type=notify
.
Type=simple
обрабатывает службу как готовую (так что заказанные для нее службы могут быть запущены / остановлены), как только процесс службы запускается, при раннем открытии сокета с использованием семантики соединения сокета для задержки клиентов службы в точках, которые они пытаются подключиться к серверам для службы, пока серверы не будут готовы.Type=notify
имеет недостаток в том, что он присущ systemd и Linux (наряду с проблемами неработоспособности из-за недолговечных процессов, таких как порождение оболочкиsystemd-notify
, и использования синтаксического анализа человеко-читаемых форм в машиночитаемые формы в привилегированном процессе, где проблемы с анализатором уже возникали в прошлом), но имеет то преимущество, что обеспечивает более точный контроль (с точки зрения служебной программы) над тем, когда служба фактически считается готовой. Он также позволяет настраивать вывод состояния.
Служебные программы обоих типов могут разветвляться. Проблема заключается в разветвлении и последующем выходе из исходного процесса .
(Следует отметить, что это такая же проблема для запуска программ из оболочек, как и для запуска программ из менеджеров служб, когда пользователи видят, что программы завершаются и почти сразу вызывают другое приглашение оболочки. Действительно, только сегодня кто-то спрашивал, еще раз , о запуске программ из оболочки, которые разветвляются и выходят из родителя, в Почему иногда, когда я запускаю программу в терминале, она не запускается в терминале?. )
Type=oneshot
вероятно, это не то, что вам нужно в данном конкретном случае, так как служба считается готовой только после того, как вся программа службы завершена. У него есть свои применения, но, судя по его звукам, они к вам не относятся.
Никогда не используйте Type=forking
. Это должно быть крайним средством отчаяния, так как практически ни одна программа не поддерживает протокол . Они делают что-то еще , что на самом деле не является этим протоколом, неправильно взаимодействует с этим протоколом и фактически не сигнализирует о готовности.
дальнейшее чтение
- Джонатан де Бойн Поллард (2001). Ошибки, которых следует избегать при разработке программ-демонов Unix . Часто задаваемые ответы.
- Джонатан де Бойн Поллард (2015). Вам действительно не нужно демонизировать. В самом деле. . Системный Дом Ужасов.
- Джонатан де Бойн Поллард (2015). Проблемы протокола готовности с демонами Unix . Часто задаваемые ответы.
- https://unix.stackexchange.com/a/401611/5132