我想在Go中实现一个“进程包装器”。基本上它会做什么,是启动一个进程(比如一个节点服务器)并监视它(捕获信号,如SIGKILL,SIGTERM ......)
我认为要做的是使用syscall.Exec
在go例程中启动节点服务器:
func launchCmd(path string, args []string) {
err := syscall.Exec(path, args, os.Environ())
if err != nil {
panic(err)
}
}
然后我想抓住由syscall
执行的命令生成的所有可能信号。我是Go的新手,任何帮助都会受到赞赏。
答案 0 :(得分:44)
在Go中有三种执行程序的方法:
syscall
包裹syscall.Exec,syscall.ForkExec,syscall.StartProcess os
包裹os.StartProcess os/exec
包裹exec.Command syscall.StartProcess是低级别的。它返回uintptr
作为句柄。
os.StartProcess
为您提供了一个很好的os.Process
结构,您可以在其上调用Signal。 os/exec
允许您io.ReaderWriter
在管道上使用。两者都在内部使用syscall
。
读取从发送的信号非自己的进程似乎有点棘手。如果可能的话,syscall
就可以做到。我没有在更高级别的包中看到任何明显的东西。
要接收信号,您可以使用signal.Notify,如下所示:
sigc := make(chan os.Signal, 1)
signal.Notify(sigc,
syscall.SIGHUP,
syscall.SIGINT,
syscall.SIGTERM,
syscall.SIGQUIT)
go func() {
s := <-sigc
// ... do something ...
}()
您只需要更改您有兴趣收听的信号即可。如果您没有指定信号,它将捕获所有可捕获的信号。
您可以使用syscall.Kill或Process.Signal来映射信号。您可以从Process.Pid
获取pid,也可以从syscall.StartProcess获得pid。
答案 1 :(得分:22)
您可以使用signal.Notify:
import (
"os"
"os/signal"
"syscall"
)
func main() {
signalChannel := make(chan os.Signal, 2)
signal.Notify(signalChannel, os.Interrupt, syscall.SIGTERM)
go func() {
sig := <-signalChannel
switch sig {
case os.Interrupt:
//handle SIGINT
case syscall.SIGTERM:
//handle SIGTERM
}
}()
// ...
}