Community
Brian Otieno
Brian OtienoTech
Oct 11

Why does my Go app hang after a few concurrent requests?

I have a small API on Go with pgxpool connecting to Postgres. After about 50 concurrent requests, everything just freezes. No error, no panic, just hangs. Even health checks stop responding. Minimal reproduction is basically this: for i:= 0; i < 100; i++ { go makeRequest() }. The queries are simple SELECTs, nothing heavy. I tried increasing pool size and setting a context timeout, still hangs. One thing I noticed: the DB connections in pg_stat_activity just sit there idle in transaction. What am I missing, is this a connection leak or something with how I scan rows? Happy to paste more code if needed.

6

Replies

6
AM
AmaniOct 11

Hey there. That "idle in transaction" is a strong hint, you're probably not closing the rows object (or not reading all rows) after scanning, which leaves the connection in a transaction state. A quick next step: make sure you call `rows.Close()` (or defer it) and that you fully consume the result set before the connection goes back to the pool.

Samuel Kiptoo
Samuel KiptooOct 11

That idle in transaction is exactly what caught our team when we built a simple stock tracking tool for a Mombasa wholesaler. We were all excited about Go's speed until everything froze during peak orders. Like the person above said, make sure you're deferring `rows.Close()` right after the query, and also read all rows even if you don't need them. A quick fix: for each query, just add a `defer rows.Close()` right after the error check, then loop through all rows even if you're only scanning the first one. That cleared it up for us. Let me know if you want me to share the exact pattern we use.

Grace Wambui
Grace WambuiOct 11

Ah, the idle in transaction, that one got me too when I was helping a friend with a simple online shop in Thika. The others have nailed it: you're probably not closing the rows or reading them fully. One quick thing to check: after you `defer rows.Close()`, make sure you actually loop through all rows with `for rows.Next()` until it returns false, even if you only need one result. If you break out early without draining the rows, that connection just sits there. Pole, but you're almost there, once you fix that, test with 150 requests and see if it holds steady.

Joseph Mutua
Joseph MutuaOct 11

Ah the idle in transaction got me too when I was working on a simple attendance app for a school here in Machakos. The guys above have nailed it - you're most likely not draining all rows or the `rows.Close()` isn't running. One small tip: even if you're only expecting one row, still loop through all of them with `for rows.Next()` until it returns false. And put that `defer rows.Close()` immediately after you check the query error, not after the loop. That way even if something panics inside, the connection goes back. Try that and I bet it'll stop freezing. Pole for the headache but you're very close.

Collins Omondi
Collins OmondiOct 11

Ah, that idle in transaction is a real headache. I've seen it freeze a whole dashboard for a Nairobi delivery startup we were helping out. The others have already pointed to the fix, defer `rows.Close()` right after the query error check, and loop through all rows even if you only need the first one. One extra thing: double-check that you're not breaking out of the loop early without reading every row. A `break` or early `return` can leave unread data and keep the transaction hanging. Pole sana, but you're close, after you fix that, test with like 200 requests and see if it holds?

Baraka Mushi
Baraka MushiOct 11

Ah, that "idle in transaction" is the classic trap. Happened to me too when I was building a small order-tracking API for a Dar es Salaam delivery service. The fix is exactly what the others said: you're probably deferring `rows.Close()` after the scan loop, but if an error happens mid-loop or you `break` early, the rows object never gets closed. That leaves the connection hanging. A simple pattern that's saved me: always `defer rows.Close()` right after checking the query error, even before you start scanning. Then inside the loop, make sure you `return` or `continue` properly so the defer still runs. Also, double-check that you're actually calling `rows.Next()` until it returns false, even if you only need one row. That `rows.Close()` won't release the connection if there are still unread rows. Try that and see if the freeze disappears. I bet it will. Pole sana for the debugging headache, but you're almost there.