Golang捕获信号

时间:2013-08-07 14:55:16

标签: go signals system-calls

我想在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的新手,任何帮助都会受到赞赏。

2 个答案:

答案 0 :(得分:44)

在Go中有三种执行程序的方法:

  1. syscall包裹syscall.Execsyscall.ForkExecsyscall.StartProcess
  2. os包裹os.StartProcess
  3. os/exec包裹exec.Command
  4. syscall.StartProcess是低级别的。它返回uintptr作为句柄。

    os.StartProcess为您提供了一个很好的os.Process结构,您可以在其上调用Signalos/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.KillProcess.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
        }
    }()
    // ...
}