Утечка горутин при выходе по таймауту из select
Обёртка над медленным поиском написана так:
func Search(ctx context.Context, q string) (Result, error) {
ch := make(chan Result)
go func() {
ch <- slowSearch(q) // без учёта ctx
}()
select {
case r := <-ch:
return r, nil
case <-ctx.Done():
return Result{}, ctx.Err()
}
}
После деградации поискового бэкенда график go_goroutines растёт линейно и не падает. Что произошло?
- Горутина завершается вместе с `Search`, а рост горутин вызван самим `select`
- Проблемы нет: `slowSearch` получит отмену через контекст и вернёт управление
- Сборщик мусора соберёт заблокированные горутины, растёт лишь показания метрики
- При срабатывании `ctx.Done()` горутина навсегда виснет на `ch <- ...`; помогает буфер размером 1
