Bug: Postgres connection pool leak on every StartClient/reconnect cycle
Commit: 9337afc (branch main, tag ~0.7.2)
File: pkg/whatsmeow/service/whatsmeow.go
Description
StartClient calls sqlstore.New(context.Background(), "postgres", w.config.PostgresAuthDB, nil) (lines ~322/329) to build the whatsmeow auth *sqlstore.Container on every invocation. This opens a brand new *sql.DB connection pool each time. container.Close() is never called anywhere in the file (confirmed with a full-file search).
StartClient is re-entered on:
ReconnectClient (line ~174), which calls StartInstance → StartClient again
- the kill-channel branch of
StartClient's own select loop (line ~629), which unconditionally calls w.StartClient(cd) again on any kill signal, not just genuine reconnect scenarios
- every new QR pairing attempt that ends in
teardownQR → kill signal → restart
Each of these paths creates a new pool that is never closed. The old pool (and any connections it opened) is simply dropped, leaking idle connections into the auth Postgres database. In production this fills max_connections (default 100) within roughly an hour of normal instance create/delete/reconnect activity, with idle connections observed sitting for days/weeks. Symptom on the client side: pq: sorry, too many clients already, and QR pairing requests timing out (504) because the container never manages to connect.
Suggested fix
Cache the *sqlstore.Container on whatsmeowService (it already holds authDB *sql.DB as a struct field) and reuse it across StartClient/ReconnectClient calls instead of building a new one each time. At minimum, defer container.Close() (or close the previous container before replacing it) on every path that currently discards it without cleanup.
Repro
- Create/delete a WhatsApp instance repeatedly (or force a few QR timeouts) against a Postgres-backed auth DB (
POSTGRES_AUTH_DB set).
SELECT count(*) FROM pg_stat_activity; on the auth DB climbs steadily with state = 'idle' rows that never close.
- Given enough cycles,
max_connections is exhausted and pairing starts failing with pq: sorry, too many clients already.
Bug: Postgres connection pool leak on every StartClient/reconnect cycle
Commit:
9337afc(branchmain, tag ~0.7.2)File:
pkg/whatsmeow/service/whatsmeow.goDescription
StartClientcallssqlstore.New(context.Background(), "postgres", w.config.PostgresAuthDB, nil)(lines ~322/329) to build the whatsmeow auth*sqlstore.Containeron every invocation. This opens a brand new*sql.DBconnection pool each time.container.Close()is never called anywhere in the file (confirmed with a full-file search).StartClientis re-entered on:ReconnectClient(line ~174), which callsStartInstance→StartClientagainStartClient's own select loop (line ~629), which unconditionally callsw.StartClient(cd)again on any kill signal, not just genuine reconnect scenariosteardownQR→ kill signal → restartEach of these paths creates a new pool that is never closed. The old pool (and any connections it opened) is simply dropped, leaking idle connections into the auth Postgres database. In production this fills
max_connections(default 100) within roughly an hour of normal instance create/delete/reconnect activity, with idle connections observed sitting for days/weeks. Symptom on the client side:pq: sorry, too many clients already, and QR pairing requests timing out (504) because the container never manages to connect.Suggested fix
Cache the
*sqlstore.ContaineronwhatsmeowService(it already holdsauthDB *sql.DBas a struct field) and reuse it acrossStartClient/ReconnectClientcalls instead of building a new one each time. At minimum,defer container.Close()(or close the previous container before replacing it) on every path that currently discards it without cleanup.Repro
POSTGRES_AUTH_DBset).SELECT count(*) FROM pg_stat_activity;on the auth DB climbs steadily withstate = 'idle'rows that never close.max_connectionsis exhausted and pairing starts failing withpq: sorry, too many clients already.