polycratia

Three seconds on an endpoint, and every query inside it runs in milliseconds: the time is not in your code. It's in the wait to get a connection.

Connection pools are the part of a backend almost nobody instruments. A handler reports how long a statement took, not how long it sat queued waiting for a connection to run that statement on. So the slow part is invisible by construction: the query log is clean, the handler looks idle, and the total still lands at three seconds.

In a marketplace backend it looks like this. One endpoint fans out across several models. An export or a reporting query holds a connection far longer than a web request ever should, and the pool is sized to the worker count. Everything else is now standing in line. Wrap an external HTTP call inside a transaction and it gets worse, because the connection stays checked out for the duration of someone else's network.

The fix is not a bigger pool. A bigger pool just moves the queue into the database.

What actually works: measure checkout wait as a first-class metric next to query time. Keep external calls outside transactions. Give long-running analytical work its own pool so it can't starve the request path.

Latency you can't attribute is latency you can't fix. Before you optimize the query, check whether the request was waiting to start it.

I unpack more of these production failure modes on my blog, if that's your kind of reading: https://polycratia.com/c/f7ab9335

Your pool probably gets held hostage somewhere first: exports, transactions wrapping network calls, or something stranger...

react

$ new-project --brief

or email hey@polycratia.com