pool.connect() emprunte une connexion : c'est au code de la rendre avec client.release().
Dans la 4.1, le chemin d'erreur return res.status(422) sort de la fonction sans ROLLBACK ni
release(). Chaque commande refusée garde donc une connexion, au milieu d'une transaction ouverte,
avec un verrou FOR UPDATE sur la ligne de stock. Après 20 refus, le pool est vide : toute requête
attend 5 secondes (connectionTimeoutMillis) puis échoue en « timeout exceeded when trying to connect ».
Les variables d'environnement étaient complètes, et PostgreSQL acceptait encore des connexions (vous
avez pu vous y connecter avec psql) : c'est le pool de l'application qui était à sec.
Incident résolu
Analyse et correction
Correction : envelopper la transaction dans try { … } catch { ROLLBACK } finally { client.release() }
(ou annuler la 4.1 avec git revert), puis pm2 reload hanout-api. En urgence, pg_terminate_backend
sur les sessions « idle in transaction » soulage, mais ne corrige rien.
Pour que cela ne recommence pas :
- pour une requête unique, utiliser
pool.query(), qui rend la connexion tout seul ; réserverpool.connect()aux transactions, toujours avecfinally; - côté PostgreSQL,
idle_in_transaction_session_timeout = '30s'pour le rôle de l'API ; - superviser le pool (
pool.totalCount,pool.idleCount,pool.waitingCount) et alerter quand des requêtes attendent ; - un test d'intégration qui enchaîne 50 commandes refusées puis vérifie que l'API répond encore.