我已使用启动和停止守护进程的包装器脚本将 LSB 控制的守护进程移植到 systemd。我的 systemd(多实例)服务文件使用Type=forking
、ExecStart=...
、ExecStop=...
和PIDFile=...
。
启动时,systemd 中一切正常,但停止似乎总是失败。由于在 LSB 环境中运行正常,我怀疑 systemd (228) 做了一些坏事。
事实上我发现在成功启动后PID 文件不见了,因此我的包装脚本返回退出代码 1(因为在预期的位置找不到 PID 文件)。
那么 systemd 真的会删除 PID 文件吗?副作用是,在包装器脚本返回错误后,systemd 似乎会强制终止我的守护进程。
答案1
是的,当服务单元进入“死亡”状态时,systemd 会删除 pidfile。然而,这种情况确实会发生后服务已停止(ExecStop 已完成且进程已终止)。
我建议不要使用 ExecStop 的包装脚本,因为...嗯,这就是 systemd 所做的。作为服务管理器,它知道您的守护进程的 PID 是什么(即使您不使用 pidfile),并且它可以本地发送信号来停止服务。
答案2
它似乎systemd
不删除PID 文件;而不是我的守护进程没有创造它由于与“旧的 init”不兼容:在 fork() 之后,我的守护进程的子进程等待父进程退出,如下所示:
while (getppid() != 1)
sleep_for_5_ms();
接下来子进程将写入 PID 文件。
如图strace
所示,getppid()
不断返回的31940
是 systemd 的 PID(systemd 还有另一个 PID 1
)。因此,systemd
一些神奇的不兼容重定位也是如此。
也许问题实际上与我的服务作为“用户”服务(而不是“系统”服务)运行有关(我仍然不确定两者的区别)。这个问题可能与以下事实有关:我怎样才能将 systemd 作为 pid 为 1 且 pid 不为 1 的进程来运行?
这也很有用:systemd 的用户服务和系统服务有什么区别?
实际上,当我将服务从用户服务更改为系统服务后,问题确实消失了。