如何跟踪 systemctl 服务生成的所有子进程

如何跟踪 systemctl 服务生成的所有子进程

我有一个系统服务

[Unit]
Description=dynsock server
After=network.target

[Service]
EnvironmentFile=/etc/dynsock.env
ExecStart=/usr/local/bin/dynctl.sh $SERVER $COUNT $BASEPORT $AUTH
ExecStop=/usr/local/bin/dynsock_onfailure.sh down
Restart=always
Type=forking

[Install]
Alias=dynsock.service

dynctl.sh将启动$count子进程。我希望当某个进程死亡时,systemctl 将重新启动并执行ExecStop。但系统只会在所有子进程死亡后才重新启动。

答案1

systemctl不可能知道dynctl.sh分叉的方式,因此无法知道在给定时间内必须有多少个子进程处于活动状态。这就是为什么您必须管理进程的生命周期,以便当一个子进程死亡时,服务将重新启动。

我建议将主进程用作master其他进程的,以便通过使用greppgrep它可以确定所有子进程是否处于活动状态,如果否,它将给出命令systemctl restart <your service>

欢呼,希望有帮助

答案2

SIGCHLD如果您有一个产生子进程的 C 或 C++ 进程,那么每当它的一个子进程死亡时,主进程就会收到信号。

默认情况下,SIGCHLD不会管理该进程,而是终止该进程。因此,如果您创建了自己的顶级进程,并且没有对该信号采取任何措施,它就会按照您的要求工作。

如果你使用另一种语言或 shell 脚本,那么SIGCHLD很可能会被管理,现在你必须监听死亡信号。这很大程度上取决于您的主进程是如何开发的。由于我看到您的服务名称以 结尾.sh,因此我认为这是一个 shell 脚本,我认为可以使用trap如下关键字来实现您的要求:

trap child_died SIGCHLD
child_died() {
   # do necessary to exit main process, I think an exit will work here
   exit 1
}
child1 &
child2 &
...
childN &

while true
do
    sleep 300
done

由于 systemd 能够了解您的所有子进程,当一个子进程退出时,它将终止所有仍在运行的进程并重新启动整个服务。

请注意,如果子代自己创建了孙代,则可以在子代中重复上述脚本,并且该级别也需要类似的功能。

警告:.service文件支持以下选项:

KillMode=process

这意味着 systemd 将不是管理您的进程子进程。您没有使用它,所以您没问题,因为默认是管理子进程。在我的终端,我有运行软件升级的服务,该升级必须由不会被终止的子进程运行,所以我使用了这个技巧。然后子进程可以更新运行升级进程的服务,而不会在中途被终止。

相关内容