11
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

goroutine は軽いですが、リークすると確実にサービスを蝕みます。

  • メモリがじわじわ増える
  • CPUが上がる
  • タイムアウトが増える
  • 再起動でしか直らない

多くの原因は「終了条件が設計されていない」ことです。
この記事は、終了条件の型と、レビューで落とせる観点をチェックリストとしてまとめます。

先に結論 起動したら停止もセット

  • goroutine を起動する場所を限定する
  • 止め方を決める
    • context.Done
    • channel close
    • 明示フラグ
  • 待ち合わせを決める
    • WaitGroup
    • errgroup

リークしやすいパターン

無限ループ + break条件なし

  • select の default で回り続ける
  • 外部APIが止まったときに永遠に待つ

受信側がいない channel 送信

  • バッファなし channel で詰まる
  • 例外経路で受信が消えて詰まる

context を渡していない

  • HTTPリクエストが切れても下流が止まらない
  • タイムアウトになっても処理が残る

実装テンプレ(最小)

context で止める

func worker(ctx context.Context, jobs <-chan Job) {
    for {
        select {
        case <-ctx.Done():
            return
        case job, ok := <-jobs:
            if !ok {
                return
            }
            _ = job
        }
    }
}

errgroup で待つ

g, ctx := errgroup.WithContext(ctx)
g.Go(func() error {
    return runA(ctx)
})
g.Go(func() error {
    return runB(ctx)
})
if err := g.Wait(); err != nil {
    // どれかが失敗
}

監視と調査の観点

  • goroutine数をメトリクス化する
  • タイムアウト率やキャンセル率を追う
  • pprof で goroutine dump を取れるようにしておく

「増えて戻らない」ならリークの可能性が高いです。

レビュー用チェックリスト

  • goroutine の停止条件がコードとして存在する
  • context が境界から渡されている
  • channel close の責務が明確
  • 送信がブロックしうる経路で、受信が必ず存在する
  • 異常系でも WaitGroup や errgroup が必ず完了する
11
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?