![Фон](https://rvso.com/image/726372/%D0%A4%D0%BE%D0%BD.png)
Фон
Меня попросили создать systemd
скрипт для новой службы, foo_daemon
которая иногда попадает в "плохое состояние" и не умирает через SIGTERM
(вероятно, из-за пользовательского обработчика сигналов). Это проблематично для разработчиков, так как им предписано запускать/останавливать/перезапускать службу через:
systemctl start foo_daemon.service
systemctl stop foo_daemon.service
systemctl restart foo_daemon.service
Проблема
Иногда, из-за того, что foo_daemon
он пришел в плохое состояние, нам приходится принудительно его убивать с помощью:
systemctl kill -s KILL foo_daemon.service
Вопрос
Как настроить systemd
скрипт foo_daemon
так, чтобы при каждой попытке пользователя остановить/перезапустить службу systemd
выполнялось следующее:
- Попытайтесь корректно завершить работу
foo_daemon
viaSIGTERM
. - Дайте время до 2 секунд на
foo_daemon
завершение работы/прекращения. - Попытайтесь принудительно завершить работу
foo_daemon
viaSIGKILL
, если процесс все еще активен (чтобы не было риска повторного использования PID иsystemd
проблемSIGKILL
с неправильным PID). Устройство, которое мы тестируем, быстро порождает/разветвляет многочисленные процессы,поэтому существует редкая, но вполне реальная обеспокоенность тем, что переработка ФИД может стать причиной возникновения проблем. - Если на практике я просто параноидально отношусь к повторному использованию PID, то меня вполне устраивает, если скрипт просто выдает
SIGKILL
команду PID процесса, не беспокоясь об остановке повторно используемого PID.
решение1
systemd уже поддерживает это из коробки, и этовключено по умолчанию.
Единственное, что вы, возможно, захотите настроить, это тайм-аут, что вы можете сделать с помощью TimeoutStopSec=
. Например:
[Service]
TimeoutStopSec=2
Теперь systemd отправит сигнал SIGTERM, подождет две секунды, пока служба не завершит работу, и если этого не произойдет, отправит сигнал SIGKILL.
Если ваша служба не поддерживает systemd, вам может потребоваться указать путь к ее PID-файлу с помощью PIDFile=
.
Наконец, вы упомянули, что ваш демон порождает много процессов. В этом случае вы можете захотеть установить KillMode=control-group
и systemd будет отправлять сигналы всем процессам в cgroup.
решение2
Поскольку никто не упомянул о необходимости Type=oneshot
, вот полный пример, который завершается из-за сбоя по тайм-ауту.
[Unit]
Description=timeout test
[Service]
Type=oneshot
TimeoutStartSec=2
ExecStart=/bin/sleep 10