![如果你的服务处于不应该被终止的状态,让 systemd 不会终止它](https://linux22.com/image/150633/%E5%A6%82%E6%9E%9C%E4%BD%A0%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%A4%84%E4%BA%8E%E4%B8%8D%E5%BA%94%E8%AF%A5%E8%A2%AB%E7%BB%88%E6%AD%A2%E7%9A%84%E7%8A%B6%E6%80%81%EF%BC%8C%E8%AE%A9%20systemd%20%E4%B8%8D%E4%BC%9A%E7%BB%88%E6%AD%A2%E5%AE%83.png)
我有一个关于 systemd 服务配置的问题。
服务应用程序是控制机器的应用程序。在应用程序中,SIGINT、SIGTERM、SIGQUIT 和 SIGHUP 被捕获。当机器处于“运行”状态时,这些信号将被忽略并且应用程序不会退出。如果机器处于“已停止”模式,则退出控制应用程序。
我们希望与 Linux 一起启动该应用程序,因此我们将该应用程序添加为 systemd 服务。
到目前为止我们有以下配置:
[Unit]
Description=Machine control service
After=network.target
[Service]
Type=simple
User=simplemachine
Group=simplemachine
CPUSchedulingPolicy=other
LimitRTPRIO=80
LimitRTTIME=infinity
WorkingDirectory=/opt/simplemachine/bin/
ExecStart=/opt/simplemachine/bin/simplemachine
KillMode=none
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
现在我有以下问题。当我执行时:
sudo systemctl stop machine.service
我希望 systemctl 发送一个 SIGTERM,这样应用程序只有在允许停止时才会停止。当应用程序不停止时也是如此。如果 systemctl 不会终止进程就好了,但是例如返回某种错误或超时代码,这意味着它可能不会停止进程。
如何使用新的 systemd 系统实现这一目标?
答案1
这个答案主要基于以下文档systemd.kill,但在做了一些测试后已更新。诚然,这并不是这个问题的完美解决方案。
通过设置SendSIGKILL=no
在您的单元文件中,可以防止进程被终止。要允许SIGTERM
发送首字母,您可能需要将该KillMode
选项恢复为其默认值,即control-group
。
通过这些设置,运行systemctl stop machine.service
应该像这样:
ExecStop=
由于单元文件中没有指定命令,因此SIGTERM
将 a 发送到进程。90 秒后 (
DefaultTimeoutStopSec
),systemd
考虑强制终止该进程。因为
SendSIGKILL
设置为no
,所以SIGKILL
(FinalKillSignal
) 是不是发送到进程,进程继续运行。
实际上,发送到进程的唯一信号systemctl stop
将是SIGTERM
。由于 的处理SIGTERM
是在应用程序本身内处理的,因此systemctl stop
应该按预期工作:当远程计算机关闭时停止应用程序,当远程计算机启动时超时。
Michał Politowski 在评论中指出了这种方法的问题。即,systemd
一旦停止超时到期,将认为该单元发生故障。这不会影响进程本身,但会改变 systemd 对进程的看法。如果您在设备处于此状态时发出另一个“systemctl start”命令,您将最终得到两个进程。
您已经使用的选项KillMode=none
完全避免了进程终止逻辑。然而,结果与此方法类似。单元的状态更改为非活动状态,而进程继续运行。
作为补充说明,90 秒超时可以配置为TimeoutStopSec
。