У меня есть служба systemd для запуска скрипта мониторинга bash, который запускается таймером systemd. Я использовал Type=oneshot
то, что кажется наиболее подходящим. Однако иногда скрипту нужно вызвать другую программу, которая, как правило, разветвляется. Как только он это делает, скрипт завершается и завершается, но как только скрипт завершается, systemd завершает все оставшиеся дочерние процессы.
Я мог бы KillMode=process
предотвратить это, но тогда есть риск, что на других путях скрипта другие процессы (которые не разветвляются) могут остаться запущенными после выхода.
Как лучше всего с этим справиться?
Кстати, программа-форк — это dhcpcd, но я думаю, что вопрос применим в целом. dhcpcd изначально был запущен ifplugd, и этот скрипт является отказоустойчивым на тот случай, если система окажется в состоянии, когда dhcpcd больше не работает.
решение1
Процессы завершаются, поскольку они принадлежат к контрольной группе (cgroup), связанной со службой, например, здесь (для системной службы):
/sys/fs/cgroup/systemd/system.slice/your-service.service
Чтобы переместить процесс из cgroup,назначить его другой cgroup. "Родительская cgroup" кажется правильной. Для системной службы это выглядит так:
echo <PID> > /sys/fs/cgroup/systemd/system.slice/tasks
# or even to the general systemd cgroup
echo <PID> > /sys/fs/cgroup/systemd/tasks
Чтобы выполнить какую-либо команду в этой cgroup с самого начала, запустите оболочку, которая назначает себя cgroup, а затем exec
переходит к фактической команде:
sh -c 'echo "$$" > /sys/fs/cgroup/systemd/tasks; exec /the/forking/program'
/the/forking/program
заменит оболочку, уже находящуюся в новой cgroup. Когда она разветвляется, разветвленный экземпляр окажется в новой cgroup. Когда основной скрипт завершит работу, systemd уничтожит процессы в cgroup, связанной со службой, но указанной программы среди них не будет.
Может быть, есть более правильный способ решить вашу проблему, с файлами юнитов или чем-то еще. Я этого не знаю.