2020/09/16

Go のアプリケーションを作っていると、シグナルの受信に伴い処理を中断したり再起動する処理を実装する事が多い。これまでは signal.Notify でシグナルをキャッチし、別途 context.WithCancel で作成したコンテキストを自ら cancel する処理を書かなければならなかった。Go の tip に入ったコミットにより、これが幾分改善される様になった。

package main

import (
    "context"
    "fmt"
    "os"
    "os/signal"
    "time"
)

func main() {
    ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
    defer stop()

    select {
    case <-time.After(time.Second):
        fmt.Println("done")
    case <-ctx.Done():
        stop()
        fmt.Println("canceled")
    }
}

このコードを実行すると、1秒経過すると done が、途中で CTRL-C をタイプすると canceled が表示される。一見、利用用途が少ない様に見えるが以下の様に goroutine を複数起動し、signal で一括終了する時には便利。

package main

import (
    "context"
    "fmt"
    "os"
    "os/signal"
    "sync"
)

func blocking(ctx context.Context, wg *sync.WaitGroup) {
    defer wg.Done()
    fmt.Println("worker started")
    <-ctx.Done()
    fmt.Println("worker canceled")
}

func main() {
    ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
    defer stop()

    var wg sync.WaitGroup
    wg.Add(3)
    go blocking(ctx, &wg)
    go blocking(ctx, &wg)
    go blocking(ctx, &wg)

    wg.Wait()
}
改訂2版 みんなのGo言語 改訂2版 みんなのGo言語
松木 雅幸, mattn, 藤原 俊一郎, 中島 大一, 上田 拓也, 牧 大輔, 鈴木 健太
技術評論社 Kindle版 / ¥2,278 (2019年08月01日)
 
発送可能時間:

Posted at 09:05 | WriteBacks () | Edit
Edit this entry...

wikieditish message: Ready to edit this entry.






















A quick preview will be rendered here when you click "Preview" button.