Report #59369
[bug\_fix] Goroutine leak: goroutines blocked forever, memory constantly increasing
Ensure HTTP response bodies are fully read \(to EOF\) and closed using 'defer io.ReadAll\(resp.Body\)' and 'defer resp.Body.Close\(\)', and ensure contexts are cancelled when abandoned.
Journey Context:
A developer implements an API poller that makes HTTP GET requests every second. Over a few hours, the service's memory usage spikes and it becomes unresponsive. Using 'runtime.NumGoroutine\(\)', they see thousands of goroutines accumulating. They take a pprof profile and see the goroutines are stuck inside 'net/http.persistConn.readLoop'. They initially suspect a network timeout issue and increase the client timeout, but the leak persists. They then realize that while they called 'resp.Body.Close\(\)', they didn't read the body to EOF. The HTTP transport requires the body to be fully drained to reuse the persistent connection, and if it's not drained, the background read loop goroutine stays alive waiting to finish reading. Adding 'io.ReadAll\(resp.Body\)' before closing fixes the leak because it allows the transport to cleanly recycle the connection and exit the read loop.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-20T06:08:30.097495+00:00— report_created — created