为了账号安全,请及时绑定邮箱和手机立即绑定

从systemd启动主进程时无法分离子进程

从systemd启动主进程时无法分离子进程

Go
慕标琳琳 2021-11-01 16:41:09
我想生成长时间运行的子进程,这些子进程在主进程重新启动/死亡时仍然存在。从终端运行时,这可以正常工作:$ cat exectest.gopackage mainimport (        "log"        "os"        "os/exec"        "syscall"        "time")func main() {        if len(os.Args) == 2 && os.Args[1] == "child" {                for {                           time.Sleep(time.Second)                }        } else {                cmd := exec.Command(os.Args[0], "child")                cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}                log.Printf("child exited: %v", cmd.Run())        }}$ go build$ ./exectest^Z[1]+  Stopped                 ./exectest$ bg[1]+ ./exectest &$ ps -ef | grep exectest | grep -v grep | grep -v vimsnowm     7914  5650  0 23:44 pts/7    00:00:00 ./exectestsnowm     7916  7914  0 23:44 ?        00:00:00 ./exectest child$ kill -INT 7914 # kill parent process[1]+  Exit 2                  ./exectest$ ps -ef | grep exectest | grep -v grep | grep -v vimsnowm     7916     1  0 23:44 ?        00:00:00 ./exectest child请注意,在父进程被杀死后,子进程仍然活着。但是,如果我像这样从 systemd 启动主进程......[snowm@localhost exectest]$ cat /etc/systemd/system/exectest.service [Unit]Description=ExecTest[Service]                        Type=simpleExecStart=/home/snowm/src/exectest/exectestUser=snowm[Install]WantedBy=multi-user.target$ sudo systemctl enable exectestln -s '/etc/systemd/system/exectest.service' '/etc/systemd/system/multi-user.target.wants/exectest.service'$ sudo systemctl start exectest...然后当我杀死主进程时,孩子也死了:$ ps -ef | grep exectest | grep -v grep | grep -v vimsnowm     8132     1  0 23:55 ?        00:00:00 /home/snowm/src/exectest/exectestsnowm     8134  8132  0 23:55 ?        00:00:00 /home/snowm/src/exectest/exectest child$ kill -INT 8132$ ps -ef | grep exectest | grep -v grep | grep -v vim$怎样才能让孩子活下来?在 CentOS Linux release 7.1.1503 (Core) 下运行 go version go1.4.2 linux/amd64。
查看完整描述

3 回答

?
qq_遁去的一_1

TA贡献1725条经验 获得超7个赞

解决方法是添加

KillMode=process

到服务区。默认值是control-group这意味着 systemd 清理任何子进程。

来自man systemd.kill

KillMode= 指定如何终止该单元的进程。控制组、过程、混合、无之一。

如果设置为 control-group,则在 unit stop 时将杀死本单元 control group 中的所有剩余进程(对于服务:执行 stop 命令后,如 ExecStop= 配置的那样)。如果设置为 process,则只会杀死主进程本身。如果设置为混合,则 SIGTERM 信号(见下文)被发送到主进程,而随后的 SIGKILL 信号(见下文)被发送到单元控制组的所有剩余进程。如果设置为 none,则不会杀死任何进程。在这种情况下,单元停止时只会执行停止命令,否则不会杀死任何进程。停止后还活着的进程留在他们的控制组中,控制组在停止后继续存在,除非它是空的。


查看完整回答
反对 回复 2021-11-01
?
慕少森

TA贡献2019条经验 获得超9个赞

如果KillMode由于某种原因你不能(像我一样)改变服务的,你可以试试这个at命令(见man)。


您可以安排您的命令提前 1 分钟运行。看一个例子:


# this will remove all .tmp files from "/path/" in 1 minute ahead (this task will run once)

echo rm /path/*.tmp | at now + 1 minute


查看完整回答
反对 回复 2021-11-01
?
青春有我

TA贡献1784条经验 获得超8个赞

据我所知,解决这个问题的唯一可行方法是使用不同的 cgroup 启动子进程。您可以使用 systemd-run 命令和 --slice 参数来做到这一点。

systemd-run --user --scope --slice=app-firefox firefox

更改 KillMode 还意味着如果您的主进程崩溃,并且任何子进程仍在运行,systemd 将不会重新启动它。


查看完整回答
反对 回复 2021-11-01
  • 3 回答
  • 0 关注
  • 146 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信