Go concurrency notes: channel and context boundaries
Go's concurrency primitives are simple; the boundaries are not. Re-reading the material with production scars, a few points finally crystallized. Writing them down before they blur again.
Channels are data flow; context is signal flow. Mixing the two -- say, plumbing cancellation through a channel -- was my most common early mistake: context cancellation cascades, hand-rolled channels do not.
Second lesson: if sync.WaitGroup solves it, do not reach for a channel. Channels are for structured producer-consumer data flow, not for acting as barriers.
ctx, cancel := context.WithTimeout(ctx, 2*time.Second)
defer cancel()
select {
case res := <-worker(ctx, req):
return res
case <-ctx.Done():
return ctx.Err()
}
And finally errgroup. It wraps WaitGroup plus context cancellation propagation exactly right, and since Go 1.20 SetLimit caps concurrency in one line. Of everything in the ecosystem, learn this one first.