HTTP Connection Leaks

Why failing to read the response body will slowly choke your server to death.

The idea

When you make an HTTP request using a connection pool (which most HTTP clients do for speed), a TCP socket is opened. To put that socket back into the pool so another request can reuse it, the HTTP Client library requires you to completely read the HTTP Response Body, and then close() it. If you check the status code (e.g., 200 OK) but forget to read/close the body, the socket is left in "limbo". It can't be reused, but it isn't destroyed. Do this 500 times, and your connection pool runs out of sockets. Your server will freeze on all future network calls. This is a Connection Leak.

Step 1: Normal. A socket is taken from the pool, used, closed, and returned.

How it works (Body Consumption)

In languages like Go, Java, and C#, reading the HTTP headers and reading the body are two separate steps. The underlying network socket cannot be reused until the body stream is fully drained and explicitly closed, signaling to the OS that you are done with the transmission.

// BAD (Go example): Connection Leak
resp, err := http.Get("https://api.example.com/status")
if err != nil { return err }
// We check the status, but forget to read or close resp.Body!
if resp.StatusCode == 200 { return true }

// GOOD: Always defer Body.Close()
resp, err := http.Get("https://api.example.com/status")
if err != nil { return err }
defer resp.Body.Close() // Guarantees the socket is returned to the pool

// If you don't need the body, explicitly discard it to drain the socket
io.Copy(io.Discard, resp.Body)
return resp.StatusCode == 200

Cost

Connection leaks are insidious because they don't crash your server immediately. They are a slow decay. Your app might run fine for 3 hours, then suddenly freeze. Monitoring tools will show low CPU and low memory, but zero throughput. The only way to detect them is to monitor "Active Connections" or "Pool Exhaustion" metrics on your HTTP clients.

Watch out for