linux 从systemd服务启动进程,该服务停止时不会终止该进程

lvmkulzt  于 2023-03-07  发布在  Linux
关注(0)|答案(1)|浏览(374)

我有一个.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杀死的方式启动一个进程?

gywdnpxw

gywdnpxw1#

Systemd在设计上会在服务应该停止时清理该服务的cgroup中的所有剩余进程-它将发送配置的KillSignal(SIGTERM),并在几秒钟后根据需要使用SIGKILL进行后续操作。
没有Start()选项可以让您的进程避免从C#代码中进行清理。在systemd .service单元级别,服务可以使用KillMode=部分选择退出清理,但有计划最终删除此选项。
启动一个需要比服务更持久的进程的正确方法是使它 * 不再是服务的一部分 *-也就是说,使用systemd D-Bus APIsystemd-run工具来a)让systemd自己启动进程作为它自己的临时服务,或者B)将您刚刚启动的进程移动到它自己的transient .scope单元中(后者不能通过systemd-run完成,只能通过D-Bus API完成)。
例如,使用Tmds.DBus(看起来比dbus-sharp维护得更活跃),将PID分离到其自己的.scope的代码可能类似于:

var bus = Tmds.DBus.Connection.System;
var sd = bus.CreateProxy<IHaveNoIdea>("org.freedesktop.systemd1",
                                      "/org/freedesktop/systemd1");
var properties = /* I don't remember how to create dicts in C# */;
properties.Add("Description", "FooBar worker process");
properties.Add("PIDs", new int[] { pid_of_worker });
properties.Add("CollectMode", "inactive-or-failed");
var aux = /* empty array? */;
var job = sd.StartTransientUnit("foobar-worker.scope", "fail", properties, aux);

(This表面上基于GNOME在gnome-desktop中使用的代码,用于将启动的应用程序从gnome-shell. service中分离。)
新的.service单元可以用类似的方法启动,但是使用ExecStart而不是PIDs(加上各种环境属性,如UserWorkingDirectory,您可能希望systemd为该进程设置这些属性)。
或者,您可以定义一个主程序可以启动的普通.service单元--如果所讨论的进程最多只需要接收一个选项(可以作为服务示例名称传递),那么这种方法就可以工作。

相关问题