Concurrency Patterns
These recurring patterns show up in nearly every real Go codebase. Recognising and applying them correctly is a key sign of Go fluency.
Pipeline
A pipeline connects processing stages with channels. Each stage reads from its input channel and writes to its output channel. The stages run concurrently:
Each stage function returns a channel โ this composable signature is the hallmark of the pipeline pattern.
Fan-Out / Fan-In
Fan-out distributes work from one channel across multiple goroutines. Fan-in merges multiple channels back into one:
Worker Pool
A worker pool keeps a fixed number of goroutines alive, each reading from a shared jobs channel. This bounds resource usage regardless of how many jobs arrive:
Key insight: closing jobs causes all workers' for range loops to exit cleanly. The WaitGroup-controlled closer then shuts down the results channel.
errgroup
golang.org/x/sync/errgroup is the idiomatic replacement for a WaitGroup when goroutines can fail:
g.Go launches a goroutine. g.Wait() blocks until all goroutines finish and returns the first error encountered. The errgroup.WithContext context is cancelled as soon as any goroutine returns an error.
Timeout with context (tying it together)
Context cancellation composes naturally with select and channels:
This pattern โ a buffered result channel, a goroutine doing work, and a select watching both the result and ctx.Done() โ appears throughout the Go standard library and ecosystem.
Knowledge Check
In a pipeline, what is the key property of each stage's function signature?
In a worker pool, why do you close the jobs channel after sending all jobs?
What does errgroup.Wait() return?