🐕

errgroupの整理

2024/08/13に公開

なぜ必要か

goroutineを作成したとき、デフォルトでは作成元はgoroutineの終了を待たない。
例えば、以下のようにmain関数を定義しても、一回もhelloが出力されないことがあり得る。

このとき、ナイーブな解決策として、channelを渡して終了を待ち合わせる。

これですべての関数呼出しを待てるようになった。しかし、関数呼出しを待つchannelをいちいち作成したりするのはかなり負担が大きい。

そこで、sync.WaitGroupを用いることで、終了を待ち合わせることができる。

ただし、どこかのgoroutineでエラーが発生したとき、その状態を把握するためにはひと工夫が必要。
ここで、errorgroupを用いることで、sync.WaitGroupで発生した最初のエラーを知ることができる。
1つでもエラーが発生したら全てのgoroutineを閉じてアプリケーションを終了するみたいな処理を実装する場合に、アプリケーションが終了した原因を知るのに便利。

使い方

func (*Group) Goでgoroutineを作成できる。
例えば、以下のようにfunc (*Group) Waitで複数goroutineを待ち合わせて、エラーがあったらそれを返す。

group, gCtx := errgroup.WithContext(ctx)
group.Go(func() error {
    // gRPCサーバーの立ち上げ
    ...
}

group.Go(func() error(
    // gRPCサーバーの終了処理
    <-gCtx.Done()
    stopped := make(chan struct{})
    go func() {
        a.RPC().GracefulStop()
        close(stopped)
}()
    ...
return group.Wait()

参考

公式ドキュメント
errgroupのはまりどころと回避策
sync.WaitGroupの正しい使い方

Discussion