我有一个系统服务
[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
其他进程的,以便通过使用grep
或pgrep
它可以确定所有子进程是否处于活动状态,如果否,它将给出命令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 将不是管理您的进程子进程。您没有使用它,所以您没问题,因为默认是管理子进程。在我的终端,我有运行软件升级的服务,该升级必须由不会被终止的子进程运行,所以我使用了这个技巧。然后子进程可以更新运行升级进程的服务,而不会在中途被终止。