Multiple workers read jobs from a channel; another stage merges results.
Fixed N goroutines pulling from jobs channel; results go to results.
Stages connected by channels; each stage does one transformation. Watch for backpressure: unbuffered stages block upstream naturally; buffered stages need sizing.
golang.org/x/sync/errgroup runs goroutines and returns the first error, with optional cancellation via context.
g, ctx := errgroup.WithContext(ctx)
for _, item := range items {
item := item
g.Go(func() error { return process(ctx, item) })
}
return g.Wait()
…share memory by communicating (Rob Pike) — but mutexes are fine when ownership is clearer than channel choreography.
Always ensure goroutines exit: tie to ctx.Done(), close upstream, or use WaitGroup.
Wrap external calls with context.WithTimeout.
Use -race in CI; stress tests with go test -count=100 for flaky ordering bugs.