Cancellation
Cancellation should propagate from the caller and stop goroutines and I/O promptly.
Canonical guidance
- caller owns cancellation intent
- pass cancellation through
context.Context - stop goroutines promptly when
ctx.Done()closes - clean up timers, channels, and spawned work
Use when
- request handlers
- background operations with deadlines
- pipelines and fan-out work
Avoid
- detached goroutines with no stop condition
- custom cancellation channels when
contextalready fits - ignoring
ctx.Err()in long-running loops
Preferred pattern
for {
select {
case <-ctx.Done():
return ctx.Err()
case item := <-in:
_ = item
}
}
Anti-pattern
go func() {
for item := range in {
process(item)
}
}()
- if nothing can stop this loop early, it can leak work
Explanation: This anti-pattern is common in rushed concurrency code because the goroutine appears independent, but without cancellation it can outlive the caller and leak work.
Why
- cancellation is a resource-management concern, not just a timeout feature
Related pages
Sources
- Go Concurrency Patterns: Context - Sameer Ajmani
- Go Concurrency Patterns: Pipelines and cancellation - Sameer Ajmani