
Я хочу написать свои собственные systemd
файлы модулей для управления действительно длительными командами 1 (порядка часов). Пока смотрюСтатья ArchWiki о systemd, в нем говорится следующее относительно выбора типа стартапа:
Type=simple
(по умолчанию): systemd считает, что служба запущена немедленно.Процесс не должен разветвляться. Не используйте этот тип, если необходимо заказать другие услуги в этой услуге, если только она не активирована через сокет.
Почему процесс вообще не должен разветвляться? Имеется ли в виду разветвление в стиле процесса вызова демона (родитель разветвляется, затем выходит) или любой вид разветвления?
1 Мне не нужен tmux/screen, потому что мне нужен более элегантный способ проверки статуса и перезапуска службы, не прибегая к tmux send-keys
.
решение1
Службе разрешено вызывать fork
системный вызов. Systemd не будет этому препятствовать и даже не заметит, если это произойдет. Это предложение относится конкретно к практике разветвления в начале демона для изоляции демона от его родительского процесса. «Процесс не должен разветвляться [и выходить из родителя во время работы службы в дочернем процессе]».
Theстраница руководстваобъясняет это более подробно и с помощью формулировок, которые не приводят к этой конкретной путанице.
Многие программы, которые должны использоваться как демоны, имеют режим (часто режим по умолчанию), в котором при запуске они изолируют себя от своего родителя. Демон запускается, вызывает fork()
, а родительский процесс завершает работу. Дочерний процесс вызывает setsid()
, чтобы он работал в своей собственной группе процессов и сеансе, и запускал службу. Цель состоит в том, что если демон вызывается из командной строки оболочки, демон не будет получать никаких сигналов от ядра или от оболочки, даже если что-то произойдет с терминалом, например, закрытие терминала (в этом случае оболочка посылает SIGHUP всем группам процессов, о которых она знает). Это также приводит к тому, что обслуживающий процесс принимается init, который пожнет его при завершении, избегаяживой мертвецесли демон был запущен чем-то, что wait()
для этого не предназначено (этого не произошло бы, если бы демон был запущен оболочкой).
Когда демон запускается процессом мониторинга, таким как systemd, разветвление контрпродуктивно. Процесс мониторинга должен перезапустить службу в случае сбоя, поэтому ему нужно знать, завершается ли служба, и это сложно, если служба не является прямым потомком процесса мониторинга. Процесс мониторинга не должен когда-либо останавливаться и не имеет управляющего терминала, поэтому нет никаких проблем с нежелательными сигналами или сбором. Таким образом, нет причин, по которым процесс службы не должен быть потомком монитора, и есть веская причина, чтобы таковым быть.
решение2
Игнорируйте эту страницу Arch Wiki.
Он имеет довольно много ошибок в отношении сеттинга Type
. Это не ограничивается только его описаниями simple
, более того. То, о чем он говорит forking
, тоже неправильно.
Правильные рекомендации для такого рода вещей существуют уже на десятилетия дольше, чем существует сам systemd, и восходят как минимум к началу 1990-х годов. Как я отметил вhttps://unix.stackexchange.com/a/476608/5132, в документации по systemd есть версия рекомендаций для демонов, которая в значительной степени повторяет то, что пользователи daemontools, IBM, люди, использующие inittab
, и ... ну ... я говорю уже десятилетиями. (Это уже был часто даваемый ответ, когда я так его описал в 2001 году.)
Повторить:
Если в вашей программе есть механизм «демонизации», который, в частности, создает потомка и завершает родительский процесс,выключиине используй это. Благодаря daemontools и др., где это было требованием в течение длительного времени, многие программы расширили возможностине иметьтакие механизмы появились более 20 лет назад, а другие просто не «демонизируются» по умолчанию, поэтому их можно использовать в режимах работы по умолчанию.
Подсистемы управления услугами запускают процессы обслуживанияв контексте демона уже. Эти процессы не нуждаются в «демонизации». (Действительно, это заблуждение во многих современных операционных системах думать, что программы дажеможет«dæmonize» из контекста сеанса входа в систему, что на самом деле и есть «dæmonization».) У них уже есть значения среды и открытые файловые дескрипторы, соответствующие контексту демона, и несколько вещей, которые фактически делает «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