eduardweb.
Ajutor & ÎntrebăriAvansat#nodejs#prisma#postgresql#ajutor

Am o eroare Prisma "Transaction already closed" în prod și am epuizat opțiunile

De Diana Oprea, 30 mai 2026 · 5 vizualizări · 3 like-uri

Postat 30 mai 2026

Salutare tuturor. Am dat de o belea pe care nu o pot replica local sub nicio formă, oricât aș stresa baza de date cu scripturi de benchmark. În producție, la un API destul de simplu care duce cam 20k de request-uri pe zi, ne trezim în Sentry cu eroarea Transaction already closed pe fluxul de checkout.

Avem un setup destul de standard: NestJS cu Prisma v5.8.0 conectat la un PostgreSQL pe AWS RDS. Tranzacția e una clasică, un $transaction interactiv în care creăm comanda, scădem stocul și generăm o factură proformă. Nimic incredibil de complex sau care să dureze secunde întregi.

Uite ce am încercat deja și nu a rezolvat problema:

1. Am mărit timeout-urile tranzacției

La început am crezut că e un simplu timeout de query. Implicit, Prisma are un timeout de 5 secunde pentru tranzacții interactive, ceea ce e destul de puțin dacă baza de date e prinsă într-un moment mai aglomerat. Am urcat valorile destul de mult, punând maxWait: 15000 (timpul de așteptare pentru a obține o conexiune din pool) și timeout: 20000 (timpul maxim de execuție a tranzacției).

Surpriza? Eroarea încă apare în loguri, uneori chiar la doar 2 secunde după ce tranzacția a fost inițiată. Deci clar nu e un timeout clasic de execuție lungă.

2. Verificarea pool-ului de conexiuni

Am suspectat că rămânem fără conexiuni libere în pool. Avem connection_limit=15 configurat în URL-ul de conexiune. Am monitorizat RDS-ul în AWS CloudWatch: utilizarea CPU-ului pe instanță nu trece de 12%, iar conexiunile active stagnează pe la 6 sau 7 simultan.

Folosim și PgBouncer în fața bazei de date (în mod session), deci n-ar trebui să avem deconectări bruște de la Postgres. Am încercat de test să legăm API-ul direct la baza de date, ocolind PgBouncer, dar eroarea a continuat să apară exact la fel.

3. Excepții ascunse în interiorul blocului

Am citit zeci de thread-uri pe GitHub. Mulți ziceau că eroarea asta apare când arunci o excepție în interiorul $transaction, Prisma încearcă să facă rollback automat, dar tu mai ai un await rătăcit pe undeva care încearcă să execute ceva pe aceeași tranzacție deja marcată ca eșuată.

Am luat la bani mărunți tot codul asincron din blocul respectiv. Nu avem forEach asincron, nu avem Promise.all dubioase în interior. Totul rulează secvențial, cu await curat la fiecare pas. Dacă un pas crapă, ar trebui să iasă direct din bloc și să prindem eroarea originală, nu chestia asta generică.

Trade-off-ul tranzacțiilor interactive

Tranzacțiile interactive din Prisma sunt excepționale ca developer experience pentru că scrii cod JS/TS normal în interiorul lor, dar am început să realizez un trade-off destul de dureros. Sunt extrem de sensibile la latența de rețea dintre serverul de API și baza de date. Dacă apare un micro-spike de rețea și motorul de Rust din spatele Prisma pierde conexiunea chiar și pentru 50ms, tranzacția este considerată moartă instant, deși Node.js încă încearcă să ruleze următorul rând de cod.

A mai lovit cineva problema asta în producție cu Prisma? Îmi scapă vreo configurare la nivel de engine sau vreo chichiță de Postgres? Orice idee e binevenită, că deja am epuizat toate ideile logice.

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

Doar membrii comunității pot lăsa comentarii.