我配置了以下服务:
[Unit]
Description=SCollector
After=NetworkManager.service
[Service]
Type=simple
ExecStart=/bin/sh -c "/opt/scollector/scollector /opt/scollector/collectors || (echo '' | /usr/bin/mail -s 'scollector died' [email protected] && exit -1)"
Restart=on-failure
[Install]
WantedBy=multi-user.target
由于某种原因,当进程以非 0 退出时,该mail
命令从不发送任何邮件。scollector
当在命令行上运行、/bin/sh
调用等时,这可以正常工作。我已经捕获了 STDOUT 和 STDERR mail
,并且它没有抛出任何错误。里面什么都没有maillog
。
是什么赋予了?为什么不发送邮件?
答案1
/usr/bin/mail
执行双重fork
守护进程sendmail
以发送电子邮件。这个sendmail
进程被重新拥有init
,所以通常它不会受到原始父进程发生的任何事情的影响 - 除了在 systemd 情况下,重新拥有的孙子仍然与原始服务位于同一个 cgroup 中。当systemd
拆除东西时,它会杀死 cgroup 内的所有进程,包括重新拥有的sendmail
进程。
该mail
命令本身运行良好,但sendmail
在它有机会执行其操作之前就被 systemd 杀死了。
KillMode
您可以通过在Unit
部分中设置process
(默认为)来解决此问题control-group
。这将导致systemd
仅终止它直接触发的进程。
有趣的是,我偶然发现这一点的方式是通过使用strace
.正常情况strace
下什么也没显示,但mail
使用时突然开始工作strace -f
。strace -f
导致主要进程一直保留,直到所有的孩子和孤儿孙子都完成。
答案2
提问者已经指出了问题;但 xyr 解决方案是一个困境,并且 xyr 对力学的描述是不正确的。
这mail
命令确实不是执行双叉。它只分叉一次,并且 sendmail shim 进程是它的直接子进程,不会重新指定任何内容的父级。它只是waitpid()
在退出之前 选择是否为该孩子服务。
sendmail shim 本身也是如此。它不会双叉。在某些 MTS 上,它甚至根本不分叉。在其他系统上,它仅分叉一次,并选择是否等待或不依赖于某些可配置的“交付模式”选项。
解决该问题的正确方法有两个:
- Set
mailx
的记录和标准化sendwait
选项。通过mailx
等待 sendmail shim 子进程完成,专门解决了异步排队问题。 (遗憾的是,尽管这个选项至少从 1986 年就已经存在,并且mailx
在 SVID 中有记录,但 bsd-mailx 没有它。但 heirloom-mailx 有它。) - 将正在使用的任何 MTS 设置为使用同步排队/传送模式(如果尚未使用)。
- 如果使用 netqmail,则不执行任何操作。 netqmail 的 sendmail shim 始终排队且同步,直接链式加载到
qmail-inject
,qmail-queue
根本不分叉。 - 如果使用 Postfix,则不执行任何操作。 Postfix 的 sendmail shim 始终排队且同步,分叉一次并等待
postdrop
完成后再退出。 - exim 有
-odf
命令行选项。
- 如果使用 netqmail,则不执行任何操作。 netqmail 的 sendmail shim 始终排队且同步,直接链式加载到
进一步阅读
- “实用程序:mailx:mailx 中的内部变量”。 壳牌与公用事业公司。单一 UNIX 规范。第 7 期。IEEE 1003.1。 2013。公开组。