从 systemd 服务调用时,接收无限标准输入的进程永远不会退出

从 systemd 服务调用时,接收无限标准输入的进程永远不会退出

我正在编写一个简单的 systemd 服务,它通过 websocket 写入输出vmstat,以便对另一个应用程序进行一些 CPU 利用率测试。我将输出传输vmstatwscat如下位置:

vmstat -n 1 | wscat localhost:1234

vmstat -n 1每秒向标准输出一条状态行。

只要我的 Web 套接字服务器在 stat 服务启动时已在监听,一切就都正常了。但如果服务器未在监听,我希望我的stat-test服务失败,然后每 10 秒自动重试一次。

但是,当我将其作为服务运行时,它wscat永远不会退出(即使失败了),所以我的服务永远不会重新启动。起初我以为出了问题,但即使我将输出通过管道传输到wscat,它仍然会挂起。vmstatnonfunction

为了简单起见,我仅发布这个最小的失败测试用例。

stat-test.sh

#!/bin/bash

vmstat -n 1 | nonfunction
echo Exited with $?

stat-test.service

[Unit]
Description=Stat-Test

[Service]
ExecStart=/bin/bash /path/stat-test.sh
Restart=always
RestartSec=10000ms

[Install]
WantedBy=multi-user.target

当我./stat-test.sh直接从终端运行时,我得到:

stat-test.sh: line 3: nonfunction: command not found
Exited with 127

但是,当我将其作为服务运行时systemctl start stat-test,我得到:

systemd[1]: Started Stat-Test.
bash[32168]: /path/stat-test.sh: line 3: nonfunction: command not found

请注意,它从不打印出退出代码。出于某种原因,失败的命令在作为服务运行时从不退出并继续运行。

但是,如果我将其更改为:echo 1 | nonfunction,服务将正常失败。因此,看起来vmstat永远运行的事实以某种方式导致它所传输的命令永远不会退出,但只有在作为服务运行时才会退出。

为什么会发生这种情况?我怎样才能使我的服务正常失败?

答案1

有一个类似的问题。 这回答

IgnoreSIGPIPE=false在文件[Service]中设置.service。摘自手册systemd.exec

IgnoreSIGPIPE=
   Takes a boolean argument. If true, causes
   SIGPIPE to be ignored in the executed process.
   Defaults to true because SIGPIPE generally is
   useful only in shell pipelines.

阅读那里的完整答案以获得解释。 在你的情况下vmstat忽略了SIGPIPE,而你不想这样做。

应用解决方案后,请echo从脚本中删除它,因为它会影响退出状态。

相关内容