我想生成长时间运行的子进程,这些进程在主进程重新启动/死亡时仍然存在。从终端运行时这很好用:
$ 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版(核心版)下运行go版本go1.4.2 linux / amd64。
答案 0 :(得分:25)
解决方案是添加
KillMode=process
到服务区。默认值为control-group
,这意味着systemd会清除所有子进程。
KillMode =指定如何杀死此单位的进程。之一 control-group,process,mixed,none。
如果设置为control-group,则控制组中的所有剩余进程 这个单位将在单位站点被杀死(服务:停止后 执行命令,如ExecStop =)所配置。如果设置为处理, 只有主要进程本身被杀死。如果设置为mixed,则为SIGTERM 信号(见下文)随后发送到主进程 SIGKILL信号(见下文)被发送到所有剩余的进程 单位的控制组。如果设置为none,则不会终止任何进程。在这 case,只有stop命令才会在单元停止时执行,但是没有 否则进程被杀死。停止后剩余的进程是 留在对照组中,对照组继续存在 停止后,除非它是空的。
答案 1 :(得分:0)
如果由于某种原因您不能(像我一样)更改服务的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