サンプルで学ぶ Go 言語:Signals

Go で書いたプログラムで Unix シグナルを受付け、処理したいことがある。 例えば、SIGTERM を受け取ったらサーバーを安全に停止したり、SIGINT を受け取ったらコマンドライン処理を中断したりといった具合である。 ここでは Go でチャネルを使ってシグナルをどう扱うのかを紹介する。

package main
import (
    "fmt"
    "os"
    "os/signal"
    "syscall"
)
func main() {

Go ではシグナルが通知されたとき、os.Signal 型の値がチャネルに届く。 これらの値を受け取るためのチャネルを作る (また、プログラムが終了できることを知らせるためのチャネルも作る)。

    sigs := make(chan os.Signal, 1)
    done := make(chan bool, 1)

signal.Notify に渡したチャネルには、指定したシグナルの通知が届くようになる。

    signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

このゴルーチンはシグナルを受信するためにブロックする。 シグナルを受信すると、それを表示し、プログラムに終了できることを知らせる。

    go func() {
        sig := <-sigs
        fmt.Println()
        fmt.Println(sig)
        done <- true
    }()

プログラムはここでシグナルが届くのを待って、終了する(シグナルが届いたことは、上のゴルーチンが done に値を送信したことから判断する)。

    fmt.Println("awaiting signal")
    <-done
    fmt.Println("exiting")
}

このプログラムを実行すると、シグナルを送るまで処理がブロックされる。 ctrl-C(ターミナルはこれを ^Cと表示する)を入力すると、シグナル SIGINT を送れる。 このシグナルを受け取るとプログラムは interrupt を表示し、終了する。

$ go run signals.go
awaiting signal
^C
interrupt
exiting

次の例:Exit