我有一个服务器进程(从systemd启动),可以启动更新过程。更新过程自我守护自身然后(理论上)用SIGTERM杀死服务器。我的问题是SIGTERM传播到更新过程,它是孩子。
出于调试目的,更新过程只是休眠,我手动发送kill。
kill之前的PS输出示例:
1 1869 1869 1869 ? -1 Ss 0 0:00 /usr/local/bin/state_controller --start
1869 1873 1869 1869 ? -1 Sl 0 0:00 \_ ProcessWebController --start
1869 1886 1869 1869 ? -1 Z 0 0:00 \_ [UpdateSystem] <defunct>
1 1900 1900 1900 ? -1 Ss 0 0:00 /bin/bash /usr/local/bin/UpdateSystem refork /var/ttm/update.bin
1900 1905 1900 1900 ? -1 S 0 0:00 \_ sleep 10000
请注意,UpdateSystem位于单独的PGID和TPGID中。 (<defunct>
进程是守护进程的结果,并且(我认为)不是问题。)
UpdateSystem是一个bash脚本(虽然我可以很容易地使它成为一个C程序,如果这将有所帮助)。从https://stackoverflow.com/a/29107686/771073获取守护程序代码后,有趣的是:
#############################################
trap "echo Ignoring SIGTERM" SIGTERM
sleep 10000
echo Awoken from sleep - presumably by the SIGTERM
exit 0
当我kill 1869
(将SIGTERM发送到state_controller
服务器进程时,我的日志文件包含:
Terminating
Ignoring SIGTERM
Awoken from sleep - presumably by the SIGTERM
我真的想阻止SIGTERM被发送到sleep
进程。
(实际上,我确实希望阻止它被发送到apt-get upgrade
,这会通过道德等同于systemctl stop ttm.service
来停止系统,而ExecStop
被指定为{ {1}} - 以防万一改变任何人的答案。)
这个问题很相似,但是接受的答案(使用/bin/kill $MAINPID
)对我来说效果不好 - 我想杀死一些子进程,而不是更新进程:
Can't detach child process when main process is started from systemd
答案 0 :(得分:2)
一种完全不同的方法是升级过程通过更新/sys/fs/cgroup/systemd
文件系统将自己从服务组中删除。特别是在bash中:
echo $$ > /sys/fs/cgroup/systemd/tasks
进程只属于一个控制组。将其PID写入根tasks
文件会将其添加到其他控制组,并将其从服务控制组中删除。
答案 1 :(得分:1)
我们决定采取的方法是在单独的(单次)服务中启动更新过程。因此,它自动属于一个单独的控制组,因此终止主服务并不会杀死它。
虽然有一个皱纹。该软件包会安装ttm.service
和ttm.template.update.service
。要运行更新程序,我们将ttm.template.update.service
复制到ttm.update.service
,运行systemctl daemon-reload
,然后运行systemctl start ttm.update.service
。为什么要复制?因为当更新程序安装新版本的ttm.template.update.service
时,它将强制终止作为该服务运行的任何进程。 KillMode=None
似乎提供了一种方法,但是虽然它似乎有效,但是随后调用apt-get会产生一个关于dpkg被中断的令人讨厌的错误。
答案 2 :(得分:1)
您确定系统没有将TERM信号发送到子进程吗?
根据服务类型,如果主进程终止,systemd将执行清理并终止同一cgroup下的所有子进程。
这是由KillMode = property定义的,默认设置为control-group。您可以将其设置为&#34; none&#34;或&#34;过程&#34;。 https://www.freedesktop.org/software/systemd/man/systemd.kill.html
答案 3 :(得分:0)
我和你有相同的意向。
升级过程是父过程的子过程。父进程由服务调用。
要点不是Cgroup,而是MAINPID。
如果使用PIDFILE分隔MAINPID,则当服务类型=分叉时,情况就解决了。
[Service]
Type=forking
PIDFile=/run/test.pid
答案 4 :(得分:0)