当前位置: 首页 > 面试题库 >

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

桓信鸥
2023-03-14
问题内容

我想产生长时间运行的子进程,这些子进程在主进程重新启动/死亡时仍然存在。从终端运行时,这工作正常:

$ cat exectest.go
package main

import (
        "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 vim
snowm     7914  5650  0 23:44 pts/7    00:00:00 ./exectest
snowm     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 vim
snowm     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=simple
ExecStart=/home/snowm/src/exectest/exectest
User=snowm

[Install]
WantedBy=multi-user.target
$ sudo systemctl enable exectest
ln -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 vim
snowm     8132     1  0 23:55 ?        00:00:00 /home/snowm/src/exectest/exectest
snowm     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版本7.1.1503(Core)下运行go版本go1.4.2 linux / amd64。


问题答案:

解决方法是添加

KillMode=process

到服务块。默认值是control-group指systemd清除所有子进程。

来自man
systemd.kill

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

如果设置为control-group,则该单元控制组中的所有剩余进程将在单元停止时被杀死(对于服务:在执行stop命令后,按ExecStop
=的配置)。如果设置为process,则仅主进程本身被杀死。如果设置为“
mixed”,则SIGTERM信号(请参阅下文)将发送到主进程,而随后的SIGKILL信号(请参阅下文)将被发送到设备控制组的所有其余进程。如果设置为none,则不会杀死任何进程。在这种情况下,只有停止命令将在单元停止时执行,否则不会杀死任何进程。停止后仍保持活动状态的进程留在其控制组中,除非停止为空,否则控制组在停止后继续存在。



 类似资料:
  • 首先,我在删除后下载了lquidbounce的源代码。gradle和我发布了代码信息,希望你们能帮我

  • 我正试图在设备上启动我的应用程序。它正在模拟器上成功发射。 null null 会不会是带有代码签名的东西? 目前我已将其设置为“不编码签名”

  • 在我连接到Docker容器后,我无法从其上分离。 我尝试用附加,但不起作用 Java进程永不结束

  • 我正在构建一个带有操作系统托盘菜单的电子应用程序。 在主进程中,我希望听到对“About”菜单项的单击,然后通知渲染器进程,以便它可以相应地更新窗口的视图。 以下是渲染窗口和任务栏菜单时的主要流程部分: 下面是应该侦听通道消息的渲染器脚本: 当我点击托盘中的“关于”菜单时,我从主进程中获得console.log输出,但我从未在渲染器进程中收到console.log或警报。 我的应用程序只有一个窗口

  • 当我试图在Android Studio中导入一个gradle项目时,我遇到了以下错误。 这是我看到的输出: 我已经关闭了在SO中的解决方案中提到的防病毒软件。但是似乎什么都不起作用。

  • 错误:无法启动守护进程。此问题可能是由不正确的守护程序配置引起的。例如,使用无法识别的 jvm 选项。请参阅守护程序的用户指南章节,http://gradle.org/docs/1.12/userguide/gradle_daemon.html VM初始化期间发生错误无法为对象堆保留足够的空间无法创建Java虚拟机。