我有一个.NET 6应用程序,它作为systemd服务在Linux上运行。这个应用程序使用如下命令执行另一个程序:
var process = Process.Start(new ProcessStartInfo
{
FileName = "foo",
Arguments = "bar",
});
这个进程应该继续运行,即使启动它的应用程序终止了。据我所知,这是Process.Start
应该做的。但在我的例子中,我现在观察到,当我通过systemctl stop
停止原始进程时,派生的进程与原始进程同时终止。
两个都在同一毫秒内停止,我为两个都被触发的AppDomain.CurrentDomain.ProcessExit
事件添加了一个处理程序,这确实表明它们都从systemd获得了一个SIGTERM。
现在,我假设systemd在这里做了一些其他的事情来清理服务,因为通常当原始进程死亡时,我所派生的进程应该继续存在。我如何才能以一种在父进程停止时不会被systemd杀死的方式启动一个进程?
1条答案
按热度按时间gywdnpxw1#
Systemd在设计上会在服务应该停止时清理该服务的cgroup中的所有剩余进程-它将发送配置的KillSignal(SIGTERM),并在几秒钟后根据需要使用SIGKILL进行后续操作。
没有Start()选项可以让您的进程避免从C#代码中进行清理。在systemd .service单元级别,服务可以使用
KillMode=
部分选择退出清理,但有计划最终删除此选项。启动一个需要比服务更持久的进程的正确方法是使它 * 不再是服务的一部分 *-也就是说,使用systemd D-Bus API或
systemd-run
工具来a)让systemd自己启动进程作为它自己的临时服务,或者B)将您刚刚启动的进程移动到它自己的transient .scope单元中(后者不能通过systemd-run完成,只能通过D-Bus API完成)。例如,使用Tmds.DBus(看起来比dbus-sharp维护得更活跃),将PID分离到其自己的.scope的代码可能类似于:
(This表面上基于GNOME在gnome-desktop中使用的代码,用于将启动的应用程序从gnome-shell. service中分离。)
新的
.service
单元可以用类似的方法启动,但是使用ExecStart
而不是PIDs
(加上各种环境属性,如User
或WorkingDirectory
,您可能希望systemd为该进程设置这些属性)。或者,您可以定义一个主程序可以启动的普通.service单元--如果所讨论的进程最多只需要接收一个选项(可以作为服务示例名称传递),那么这种方法就可以工作。