Skip to content

Raise the DB connection pool off its development default - #193

Merged
ssavutu merged 1 commit into
mainfrom
fix/db-pool-size
Aug 6, 2026
Merged

Raise the DB connection pool off its development default#193
ssavutu merged 1 commit into
mainfrom
fix/db-pool-size

Conversation

@ssavutu

@ssavutu ssavutu commented Aug 6, 2026

Copy link
Copy Markdown
Member

Production is currently down behind this. Merging deploys the fix.

What happened

database.go capped the pool at SetMaxOpenConns(10). Scalene calls /v1/settings/site on every page render, so under public traffic those requests serialize behind ten connections. On the cutover that endpoint was taking 25–125 seconds, Scalene's fetches returned Cloudflare 524, and www timed out entirely.

Why it was hard to spot

Every host reported idle:

host state
Delta (CMS) load 0.02, 9.6 GB free
DB1 14 of 200 connections, 2 running threads
MaxScale 3.9 GB of 4 GB free, both nodes in sync
.141 (WordPress + Astro) load 0.57, 10.6 GB of 12 GB free

The database is idle because only ten requests can reach it at once. The contention is in the queue in front of it, and no host metric names that queue — which is what makes this look like a resource shortage on some other machine.

The inactive blue/green slot answered /v1/health/db in 0.5 ms throughout, purely because it was serving no traffic. That contrast is the tell.

The change

Default 50, overridable with DB_MAX_OPEN_CONNS. DB1 allows 200 connections, so two slots at 50 leaves headroom for MaxScale's monitor, the replica, and an operator session. The env override exists because this only reproduces under real traffic.

Follow-up worth doing separately

/v1/settings/site is a per-render call on a value that changes rarely; a short TTL cache would cut the query volume by orders of magnitude regardless of pool size. Not in this PR — this one should stay minimal enough to merge while the site is down.

Verified: go build ./..., go vet, go test ./internal/database/ all clean.

🤖 Generated with Claude Code

The pool was ten connections. That is survivable for a single editor and fatal
under public traffic: Scalene calls /v1/settings/site on every page render, and
with ten connections those requests serialize behind each other. Measured on the
public cutover, /v1/settings/site took 25-125 seconds and the site timed out
behind Cloudflare 524s.

What makes this hard to see is that nothing looks busy. The database was at two
running threads and 14 of 200 connections, the CMS host at 0.02 load, the
database host and MaxScale both nearly idle. Every machine reports plenty of
headroom, because the contention is in the queue in front of the database rather
than in the database itself -- the pool is a limit the metrics do not mention.

Default is now 50. DB1 allows 200, so two blue/green slots at 50 leaves room for
MaxScale's monitor, the replica, and an operator session. DB_MAX_OPEN_CONNS
overrides it, because this failure mode only appears under real traffic and
resizing the pool should not require a rebuild.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ssavutu
ssavutu merged commit e3a2f18 into main Aug 6, 2026
6 checks passed
@ssavutu
ssavutu deleted the fix/db-pool-size branch August 7, 2026 04:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant