web-dev-qa-db-ja.com

Golangキャッチ信号

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にかなり慣れていないので、どんな助けでもいただければ幸いです。

20
rmonjo

Goでプログラムを実行する方法は3つあります。

  1. syscallパッケージ syscall.Execsyscall.ForkExecsyscall.StartProcess
  2. osパッケージ os.StartProcess
  3. os/execパッケージ exec.Command

syscall.StartProcess は低レベルです。 uintptrをハンドルとして返します。

os.StartProcessは、呼び出しが可能なos.Process構造体 Signal onを提供します。 os/execは、パイプで使用するio.ReaderWriterを提供します。どちらも内部でsyscallを使用します。

送信されたシグナルを読み取るfrom自分以外のプロセスは少し難しいようです。可能であれば、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 を使用して信号をマッピングします。 pidはProcess.Pidから、または syscall.StartProcess から結果として取得できます。

45
Luke

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
        }
    }()
    // ...
}
22
Baba