Перезапуск Systemd = всегда не соблюдается

54

Примечание. Я написал статью на Medium, в которой объясняется, как создать службу и как избежать этой конкретной проблемы: создание службы Linux с помощью systemd .

Оригинальный вопрос:


Я использую systemd, чтобы рабочий скрипт всегда работал:

[Unit]
Description=My worker
After=mysqld.service

[Service]
Type=simple
Restart=always
ExecStart=/path/to/script

[Install]
WantedBy=multi-user.target

Хотя перезапуск работает нормально, если сценарий завершается нормально через несколько минут, я заметил, что, если он неоднократно не systemdзапускается при запуске, просто перестану пытаться запустить его:

Jun 14 11:10:31 localhost systemd[1]: test.service: Main process exited, code=exited, status=1/FAILURE
Jun 14 11:10:31 localhost systemd[1]: test.service: Unit entered failed state.
Jun 14 11:10:31 localhost systemd[1]: test.service: Failed with result 'exit-code'.
Jun 14 11:10:31 localhost systemd[1]: test.service: Service hold-off time over, scheduling restart.
Jun 14 11:10:31 localhost systemd[1]: test.service: Start request repeated too quickly.
Jun 14 11:10:31 localhost systemd[1]: Failed to start My worker.
Jun 14 11:10:31 localhost systemd[1]: test.service: Unit entered failed state.
Jun 14 11:10:31 localhost systemd[1]: test.service: Failed with result 'start-limit'.

Точно так же, если мой рабочий скрипт несколько раз завершается сбоем со статусом выхода 255, systemdпрекращает попытки его перезапустить:

Jun 14 11:25:51 localhost systemd[1]: test.service: Failed with result 'exit-code'.  
Jun 14 11:25:51 localhost systemd[1]: test.service: Service hold-off time over, scheduling restart.  
Jun 14 11:25:51 localhost systemd[1]: test.service: Start request repeated too quickly.  
Jun 14 11:25:51 localhost systemd[1]: Failed to start My worker.  
Jun 14 11:25:51 localhost systemd[1]: test.service: Unit entered failed state.  
Jun 14 11:25:51 localhost systemd[1]: test.service: Failed with result 'start-limit'.

Есть ли способ , чтобы заставить , systemdчтобы всегда повторить через несколько секунд?

Вениамин
источник

Ответы:

53

Я хотел бы немного расширить ответ Рахула.

SystemD пытается перезапустить несколько раз ( StartLimitBurst) и прекращает попытки, если количество попыток достигнуто в течение StartLimitIntervalSec. Оба варианта принадлежат [unit]разделу.

Задержка по умолчанию между выполнениями составляет 100 мс ( RestartSec), что приводит к очень быстрому достижению предела скорости.

SystemD больше не будет пытаться выполнить автоматический перезапуск для устройств с определенной политикой перезапуска :

Обратите внимание, что блоки, для которых настроено Restart=и которые достигают предела запуска, больше не пытаются перезапускаться; однако, они все равно могут быть перезапущены вручную позже, после чего логика перезапуска снова активируется.

Ответ Рахула помогает, потому что более длительная задержка препятствует достижению счетчика ошибок во StartLimitIntervalSecвремени. Правильный ответ - установить RestartSecи StartLimitBurstразумные значения.

Marsik
источник
5
Теперь, когда я (наконец) понял, как это работает, после некоторых проб и ошибок я вижу, что ваш ответ является наиболее правильным. Итог для меня: установить StartLimitIntervalSec=0и вуаля.
Бенджамин
35

Да , есть. Вы можете указать, чтобы повторить через xнесколько секунд в [Service]разделе,

[Service]
Type=simple
Restart=always
RestartSec=3
ExecStart=/path/to/script

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

systemctl daemon-reload

затем перезапустите службу, чтобы включить изменения,

systemctl restart test

Как вы просили, глядя на документацию,

Restart=on-failure

звучит как достойная рекомендация.

Рахул
источник
Похоже, действительно работает, спасибо! Таким образом, чтобы лучше понять это, без RestartSecдирективы, systemdнесколько попыток перезапускается очень быстро, затем переходит в состояние постоянного сбоя; то, что не может произойти, когда RestartSecуказано?
Бенджамин
Кроме того, я заметил, что это задерживает «нормальный» перезапуск моего работника (я целенаправленно покидаю работника через несколько минут); Есть ли способ отложить только неудачный перезапуск?
Бенджамин
@ Бенджамин посмотреть мои обновления
Рахул
@ Бенджамин, вы можете проверить здесь для получения дополнительных параметров.
Рахул
3
Судя по документу , alwaysэто суперсет on-failure, так что не поможет!
Бенджамин
5

systemd прекращает попытки перезапустить его

Нет. Systemd перестает пытаться перезапустить его на некоторое время . Это ясно показано в журнале, который вы предоставляете:

14 июня, 11:25:51 localhost systemd [1]: test.service: не удалось с результатом 'start-limit' .

Это ограничение скорости.

Длина небольшого времени указывается в сервисном блоке, используя StartLimitIntervalSec=настройки. Количество пусков, которое необходимо в этом интервале для запуска механизма ограничения скорости, указывается через StartLimitBurst=настройку. Если ничто в вашей системе не отличается от vanilla systemd, включая значения по умолчанию для этих двух настроек, то это будет 5 раз в течение 10 секунд.

StartLimitIntervalSec=0отключает ограничение скорости, поэтому systemd будет повторять попытки бесконечно, а не сдаваться. Но лучше сделать так, чтобы ваш сервис не выходил так часто или оставался достаточно простоя между выходами и перезапусками, чтобы он не превышал порог ограничения скорости.

Обратите внимание, что ограничение скорости не имеет значения, как вышла ваша служба. Это вызывает количество попыток запустить / перезапустить его, независимо от их причины.

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

JdeBP
источник
5
Похоже, что он постоянно сдается: «Активно: не удалось (Результат: старт-лимит) с ср. 2016-06-15 01:21:24 CEST; 12h тому назад». Он остается в этом состоянии, и скрипт никогда не выполняется снова. Я попытался установить вручную StartLimitIntervalSec=10и StartLimitIntervalSec=5, не повезло.
Бенджамин
5
По умолчанию он сдается навсегда. См. Github.com/systemd/systemd/issues/2416 .
Адам Гуд
2
Итог: чтобы остановить, чтобы он не сдавался навсегда, установите StartLimitIntervalSec=0.
Бенджамин