How does errgroup.WithContext use context, and what is a common bug with it?
Question 282HardGo 1.22 to 1.25
errgroup.WithContext(parent) (from golang.org/x/sync/errgroup) returns a group and a derived ctx. That ctx is canceled the first time a goroutine returns a non-nil error, or when Wait returns, whichever happens first. The error is recorded as the context's cause, and Wait returns the first error. SetLimit(n) bounds concurrency.
func fetchAll(ctx context.Context, urls []string) ([][]byte, error) {
g, ctx := errgroup.WithContext(ctx)
g.SetLimit(8)
out := make([][]byte, len(urls))
for i, u := range urls { // Go 1.22: i and u are per-iteration
g.Go(func() error {
b, err := fetch(ctx, u) // siblings abort once one fails
if err != nil {
return fmt.Errorf("%s: %w", u, err)
}
out[i] = b // distinct index per goroutine: no race
return nil
})
}
if err := g.Wait(); err != nil {
return nil, err
}
return out, nil
}
Common bugs:
- Shadowing and reusing
ctxafterWait(). The lineg, ctx := errgroup.WithContext(ctx)replaces the outerctx, and that derived context is always canceled onceWaitreturns. Any later call in the same function that usesctxfails with "context canceled". Name itgctx, or keep the group in a separate function. - Goroutines that ignore
ctx. Cancellation then does nothing, andWaitstill blocks until the slowest goroutine finishes.
More on Context
- Q280Write a function that runs a blocking call with a context and returns early on cancellation. What goroutine leak must you avoid?
- Q281How should a long-running worker loop respect cancellation? Discuss select fairness and CPU-bound loops.
- Q283How would you merge two contexts so the result is canceled when either one is?
- Q284Can you implement your own Context type? How does the stdlib propagate cancellation from a custom parent?
- Q285How do deadlines propagate across service boundaries (e.g., gRPC), and how do you manage a time budget across multiple downstream calls?
- Q286How do you implement graceful shutdown with signal.NotifyContext, and what context mistake defeats it?