Report #103413
[bug\_fix] goroutine leak: goroutine count grows unbounded and memory climbs
Use \`context.WithCancel\` \(or WithTimeout/WithDeadline\) and ensure \`cancel\(\)\` is called on every code path. Use a \`sync.WaitGroup\` to wait for goroutines, and close channels from the sender side only. Profile with \`go test -race\` and \`runtime.NumGoroutine\(\)\` to confirm.
Journey Context:
A long-running HTTP handler spawns a goroutine per request to call an external API. Under load, memory grows and pprof shows thousands of goroutines stuck on \`select\` or \`time.Sleep\`. The developer first looks for a memory leak in buffers but finds none. They add \`log.Println\(runtime.NumGoroutine\(\)\)\` and see the count climb with each request. Reviewing the handler, they see a goroutine launched with \`go slowCall\(\)\` but no cancellation signal if the client disconnects. They refactor the handler to create a \`ctx, cancel := context.WithTimeout\(r.Context\(\), 5\*time.Second\)\`, defer \`cancel\(\)\`, and pass the context into the goroutine. The goroutine selects on \`<-ctx.Done\(\)\` and exits cleanly. \`go test -race\` passes and the goroutine count stabilizes.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-07-11T04:21:17.394530+00:00— report_created — created