Можно ли указать зависимость systemd от одного из нескольких модулей?
В настоящее время у меня есть единица Z, которая зависит хотя бы от одного из единиц A или B.
Настройка блока A как WantedBy
единица Z и единица B должны быть WantedBy
блок Z в основном работает.
Однако, если только один из модулей A или B может запуститься, процесс загрузки ожидает тайм-аута другого модуля, прежде чем запускать модуль Z. Я хочу исключить этот тайм-аут.
Модулям A и B требуется тайм-аут для правильной работы, однако, как только один из них запущен, нет необходимости ждать, пока другой модуль не истечет, прежде чем запускать модуль Z.
Есть ли способ указать, что блок Z зависит от блока A или блока B, но не нужно ждать одновременно блока A и блока B перед запуском блока Z?
В мире Debian система упаковки использует Provides
чтобы указать что-то похожее на то, что я надеюсь здесь достичь.
Debian раньше поддерживал keyscript
вариант в crypttab
но не повторно реализовал эту опцию, когда апстрим переписывал сценарии запуска для перехода на systemd
. Раньше я использовал keyscript
чтобы прочитать мой ключ с USB-накопителя. В настоящее время я использую systemd
unit файл, чтобы заменить keyscript
вариант (блок А). Это прекрасно работает. Однако USB-накопители подвержены сбоям, поэтому для обеспечения избыточности я хочу перенести вторую копию моего ключа на второй USB-накопитель. И я хочу добавить второй systemd
unit для этого второго USB-накопителя (модуль B), так что какой бы USB-накопитель ни был вставлен, systemd
может использовать этот USB-накопитель и продолжить работу без тайм-аута.
С помощью Conflicts
чтобы указать, что A конфликтует с B, а B конфликтует с A. К сожалению, systemd обрабатывает конфликт перед попыткой запуска любого из модулей A или B и удаляет один из этих модулей из планировщика, прежде чем пытаться запустить оставшийся модуль. Таким образом, Z иногда терпит неудачу, например, если терпит неудачу A, но B добился бы успеха, если бы B уже был исключен из рассмотрения из-за конфликта с A.
С помощью JobTimeoutSec
чтобы сократить время ожидания. К сожалению, это может привести к сбою Z, если таймаут A и B.
Предложения Майкла Хэмптона. Как он упоминает, пример NTP создает слабую зависимость между каждым клиентом и целью. Каждому клиенту NTP нужна цель, но цель не зависит от каждого из клиентов NTP, поэтому это работает. Однако, насколько я могу судить, слабая зависимость не влияет на единицу, если она не имеет [Install]
раздел, определяющий дополнительную зависимость. Поэтому, когда я подтягиваю свои блоки A и B, WantedBy
в [Install]
секция создает таймаут блокировки. Если я удалю [Install]
раздел, блоки A и B игнорируются.
Это работа для целевого юнита systemd.
Вместо того, чтобы приводить надуманный пример, я приведу реальный пример, который уже присутствует в вашей системе.
Рассмотрим NTP. Большинство компьютеров синхронизируются через NTP, но есть три (а может и больше) клиента NTP, из которых вы можете выбрать: systemd-timesyncd, chronyd или (классический) ntpd.
Каждый из сервисных модулей для этих клиентов NTP является частью цели, называемой time-sync.target
, и слабо требует этого как такового.
Before=time-sync.target
Wants=time-sync.target
Таким образом, когда вы запускаете любой из клиентов NTP, time-sync.target
запускается после запуска клиента NTP. Обратите внимание, что time-sync.target
сам по себе пуст и фактически ничего не делает сам по себе.
Итак, если вы запускаете службу, которая требует, чтобы системное время было синхронизировано, и в противном случае выйдет из строя, вы можете потребовать, чтобы она запускалась только после time-sync.target
началось.
After=time-sync.target
Requires=time-sync.target
Вы легко сможете адаптировать это к своему собственному сервису.
Я думаю, если бы эта функция существовала, она была бы в systemd.unit
справочную страницу, и я не вижу ее там.
Решением может быть использование небольшого bash
сценарий, который завершается успешно, как только запускается A или B, или терпит неудачу, если оба A и B не запускаются.