Explain errgroup: WithContext, SetLimit, TryGo. What are its semantics and gotchas?
Question 244HardGo 1.22 to 1.25
golang.org/x/sync/errgroup is a WaitGroup plus error propagation plus cancellation.
g.Go(f)runsfin a goroutine.g.Wait()blocks until all functions return, then returns the first non-nil error.WithContextderives a context that is cancelled on the first error or whenWaitreturns.SetLimit(n)bounds the number of active goroutines;Goblocks when the limit is reached.TryGois the non-blocking version and returns false at the limit.
func FetchAll(ctx context.Context, urls []string) ([]Page, error) {
g, ctx := errgroup.WithContext(ctx)
g.SetLimit(8)
pages := make([]Page, len(urls))
for i, u := range urls {
g.Go(func() error {
p, err := fetch(ctx, u) // must honor ctx to stop early
if err != nil {
return fmt.Errorf("fetch %q: %w", u, err)
}
pages[i] = p // distinct indices: no race
return nil
})
}
if err := g.Wait(); err != nil {
return nil, err
}
return pages, nil
}
Gotchas:
- Cancellation is cooperative. If your functions ignore
ctx, they keep running after the first error. - Only the first error is kept. Use
errors.Joinyourself if you need all of them. - The group context is cancelled as soon as
Waitreturns. Shadowingctx(as above) hides the parent, so any code afterWaitthat still usesctxsees an already-cancelled context. Name itgctxif you need the parent afterwards. - Calling
SetLimitwhile goroutines are active panics. - errgroup does not turn panics into errors. Do not rely on it to recover them; if a panic in
fmust become an error,recoverinsidef.
More on Concurrency Patterns & sync
- Q242How do you close a channel safely when there are multiple senders?
- Q243How do you implement a semaphore in Go? Compare a buffered channel with golang.org/x/sync/semaphore.
- Q245You need to process 10 million records from a file with bounded memory and bounded parallelism. How do you design it?
- Q246How do you implement rate limiting in Go? Compare time.Ticker with golang.org/x/time/rate.
- Q247What problem does singleflight solve, and what are its gotchas?
- Q248Implement graceful shutdown for an HTTP server with background workers.