Lesson 26 · Senior Go backend engineering
errgroup & bounded concurrency
The senior answer when work can fail, cancel siblings, or arrive in huge batches.
Your win: know when errgroup is better than WaitGroup, explain fail-fast fan-out in plain English, and describe bounded concurrency the way a senior backend engineer would — as overload control, not just as a syntax trick.
errgroup fills.
Why this matters beyond syntax
The difference between junior and senior concurrency answers is often not “knows more packages.” It is “can explain lifecycle.” Who starts the work? Who cancels it? Who owns the first failure? What stops the input size from turning into unbounded goroutines?
WaitGroup answers “have these goroutines finished yet?”
errgroup answers “how does this whole concurrent operation succeed, fail, and stop?”
The shape of an errgroup operation
g, ctx := errgroup.WithContext(ctx)
g.SetLimit(8)
for _, job := range jobs {
job := job
g.Go(func() error {
return process(ctx, job)
})
}
if err := g.Wait(); err != nil {
return err
}
- Shared cancellation — first failure can stop sibling work
- Error propagation — the caller gets a meaningful result
- Bounded concurrency — large inputs do not automatically create unlimited goroutines
errgroup-shaped operation that fails fast under one parent context?”
WaitGroup for work that can fail. If one child errors and the others keep chewing CPU, memory, or downstream capacity, you do not have structured concurrency — you have cleanup debt.
Pipelines, cancellation, and x/sync
The Go blog gives the cancellation story; errgroup is the practical helper that makes that story ergonomic in production code.
→ go.dev/blog/pipelines
→ pkg.go.dev/golang.org/x/sync/errgroup
Check yourself (from memory)
Q1. The senior reason to prefer errgroup over WaitGroup is…
Q2. Bounded concurrency protects a service from…
WaitGroup, worker pools, semaphores, and errgroup? Ask me.
Sources. Pipelines and cancellation; errgroup docs.