• node.js怎么可以在关闭 exec.Command 打开的进程时保证关闭所有的子进程
  • 发布于 1周前
  • 36 热度
    4 评论

如题,比如代码这样的:

func command(command string, writer io.Writer, notify chan struct{}) {
r, w := io.Pipe()

cmd := exec.Command("bash")
cmd.Dir = "/data"
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} # 这个还不兼容 windows

cmd.Stdin = r

stdout, _ := cmd.StdoutPipe()
stderr, _ := cmd.StderrPipe()
defer stdout.Close()
defer stderr.Close()

cmd.Start()
go trans(stdout, writer) // iocopy
go trans(stderr, writer)

go func() {
<-notify
fmt.Println(cmd.Process.Kill())
w.Close()
}()

fmt.Fprint(w, command)
w.Close()

cmd.Wait()
}
如果执行 yarn build 会执行一个 nodejs 的构建,但是当 notify 通知后,bash 进程退出了。nodejs 进程僵尸了。怎么保证所有由 bash 开启的所有子进程都被关闭(哪怕强制退出)?
用户评论
  • 浅歌
  • 我记得这个问题曾经让我很头疼,原因是 go 进程开启了 bash ,bash 执行 git ,git 又启动了子进程,但是最终产生了大量的 defunct 状态的进程项,也就是说进程已经销毁了,但是 pid 还留在注册表上,导致最终系统无法再新建进程。
    最后的解决方法与 go 没有关系,这个问题似乎是 git 的问题,我起了一个定时任务,定期检查 fefunct 的进程项,然后通过调用 wait 强行把它们从进程表中删除。
  • 2024/4/8 9:20:00 [ 0 ] [ 0 ] 回复
  • 褪色时间
  • 之前调查过这个问题,不同操作系统情况不同:
    POSIX(Linux 除外)似乎没有通用方法。杀进程组的话,子进程可以创建新的进程组来避免。杀进程树的话,子进程可以 fork 两次来脱离进程树。
    Linux 可以用 PID namespace 来实现,当一个 PID namespace 里面的“init”进程退出后,其他进程都会被停止。
    Windows 可以用 Job Object 实现。
  • 2024/4/8 9:19:00 [ 0 ] [ 0 ] 回复