シグナルを受け取ってgorutineの終了を待ってからプログラムを終了する

件名の通り。

DBアクセスなどプログラム終了前に走り切らせたい処理を定期起動するプログラムでは、終了のためのシグナルを受け取ったらその定期起動するためのgoroutineを終わらせてからプログラムを終了したい。

package main

import (
    "context"
    "log"
    "os"
    "os/signal"
    "time"
    "sync"
    "syscall"
)

func main() {
    var wg sync.WaitGroup
    ctx, cancel := context.WithCancel(context.Background())
    wg.Add(1)
    go func() {
        defer wg.Done()
        loop(ctx)
    }()

    log.Println("シグナルを受け付ける")
    sigChan := make(chan os.Signal, 1)
    signal.Notify(sigChan)
    flag := true
    for flag {
        sig:= <-sigChan
        log.Println("シグナルを受け取った", sig)
        switch sig {
            case syscall.SIGURG:
                log.Println("無視")
            default:
                log.Println("シグナル待ちをやめる")
                flag = false
        }
    }
    log.Println("goroutineを停止する")
    cancel()
    log.Println("goroutineの終了を待つ")
    wg.Wait()
}

func loop(ctx context.Context) {
    for {
        select {
        case <-ctx.Done():
            log.Println("goroutineのキャンセルを検出!")
            return
        default:
            log.Println(time.Now().Local(), "何かしらの処理")
            time.Sleep(time.Second)
        }
    }
}