我有一个服务器进程(从systemd启动),可以启动更新过程。 更新过程自我守护,然后(理论上)用SIGTERM杀死服务器。 我的问题是,SIGTERM传播到更新过程,它是孩子 。
为了debugging的目的,更新过程只是睡觉,我发送杀手。
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
的道德等价物来systemctl stop ttm.service
,而ExecStop
被指定为/bin/kill $MAINPID
– 以防万一,回答。)
这个问题是类似的,但接受的答案(使用KillMode=process
)不适合我 – 我想杀死一些subprocess,而不是更新进程: 主进程启动时不能分离subprocess从systemd
升级过程通过更新/sys/fs/cgroup/systemd
文件系统将其自身从服务组中删除是一种完全不同的方法。 特别是在bash中:
echo $$ > /sys/fs/cgroup/systemd/tasks
一个进程只属于一个控制组。 将其PID写入根tasks
文件将其添加到其他控制组,并将其从服务控制组中删除。
你确定它不是systemd发送TERM信号到子进程吗?
根据服务类型的不同,如果你的主进程死了,systemd将会进行清理并终止同一个cgroup下的所有子进程。
这是由默认设置为控制组的KillMode =属性定义的。 您可以将其设置为“无”或“处理”。 https://www.freedesktop.org/software/systemd/man/systemd.kill.html
我们决定采用的方法是在单独的(单次)服务中启动更新过程。 因此,它自动属于一个单独的控制组,因此杀死主要服务不会杀死它。
这虽然有一个皱纹。 该软件包安装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被中断的令人讨厌的错误。