
Golang: 手軽にシグナルをListenしてcallback関数を呼ぶ
Go言語でシグナルを取り扱いたい場合、osパッケージおよびos/signalパッケージ、syscallパッケージを使用します。 具体的には、以下のようにします。 1 2 3 4 5 6 7 8 9 10 11 12 13 func main() { sigCh := make(chan os.Signal, 1) doneCh := make(chan struct{}) signal.Notify(sigCh, syscall.SIGINT) go func() { sig := <-sigCh fmt.Println(sig) // (1) close(doneCh) }() <-done } 実際には、(1)の様に受け取ったシグナルを出力するだけではなく、何らかの処理を行うことになるでしょうし、goroutineのリークを避けるためにシグナルの待受をキャンセルする必要が有りますから、contextを使用してfor-selectループを書くことにもなるでしょう。 例として、HTTPサーバをシャットダウンするような処理を考えます。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 func main() { sigCh := make(chan os.Signal, 1) doneCh := make(chan struct{}) ctx, cancel := context.WithCancel(context.Background()) signal.Notify(sigCh, syscall.SIGINT) s := &http.Server{ Addr: ":8080", Handler: http.DefaultServeMux, } go func() { for { select { case sig := <-sigCh: sig := <-sigCh s.Shutdown(context.Background()) close(doneCh) case <-ctx.Done(): return } } }() if err := s.ListenAndServe(); err != http.ErrServerClosed { log.Println(err) cancel() return } <-doneCh } シグナルを受け取って、関数の呼び出し(ここではs.Shutdown())をしたいだけなのに、チャンネルを作って、goroutineを立ち上げて、となんとも大仰です。 goroutineで呼び出す関数の中でfor-selectループを使っているため、行数も長くなってしまっています。 ...