eduardweb.
Ajutor & ÎntrebăriIntermediar#prisma#postgresql#nestjs#aws-rds

Prisma îmi dă „Transaction already closed” în producție și nu-i dau de cap

De Ioana Marinescu, 16 iun. 2026 · 21 vizualizări · 3 like-uri

Postat 16 iun. 2026

Salutare tuturor. M-am lovit de o problemă destul de ciudată cu Prisma în producție și sincer sunt la capătul puterilor, așa că apelez la experiența voastră. De vreo două săptămâni ne tot crapă tranzacțiile random cu eroarea Transaction already closed, deși pe staging totul rulează perfect și nu reușim să reproducem comportamentul local sub nicio formă.

Avem un API scris în NestJS pe un proiect cu vreo 12k utilizatori activi zilnic. Nu este un trafic uriaș, dar avem un flux de checkout destul de complex unde scriem în vreo 4 tabele în cadrul aceleiași tranzacții interactive. Baza de date este un PostgreSQL găzduit pe AWS RDS, mai exact o instanță db.t3.medium care stă de obicei destul de relaxată.

Ce am încercat deja și n-a funcționat

Prima mea reacție a fost să bănuiesc un timeout clasic de rețea sau de query. Am mărit parametrii pentru tranzacțiile interactive direct în cod, sperând că rezolvă problema:

await prisma.$transaction(async (tx) => {
  // query-uri de checkout
}, {
  maxWait: 10000, // 10 secunde
  timeout: 20000  // 20 secunde
})

Nicio schimbare. Eroarea continuă să apară complet aleatoriu, uneori după doar 2-3 secunde de la inițierea tranzacției, deci mult sub pragul de timeout setat de noi în cod.

Apoi m-am gândit la o problemă de connection pool. Am modificat connection_limit în string-ul de conexiune, urcându-l de la 10 la 25. Rezultatul? Doar am mutat problema în altă parte. CPU-ul pe RDS a început să aibă spike-uri mai mari în orele de vârf, dar frecvența erorilor de tranzacție a rămas exact aceeași. Am revenit rapid la valoarea de 15.

Am luat la bani mărunți tot codul din interiorul tranzacțiilor. Știu că Prisma este extrem de sensibilă dacă ai promisiuni care nu sunt rezolvate cu await în interiorul callback-ului de tranzacție. Am verificat fiecare query, fiecare map de promisiuni, totul este await-uit corect. Nu avem operații asincrone "uitate" pe fundal care să ruleze după ce tranzacția se închide.

Am analizat și logurile din APM (folosim Datadog). Tot ce vedem este că eroarea e aruncată brusc, fără un query lent premergător. Uneori se întâmplă pe query-uri banale de tip SELECT care în mod normal durează 5 milisecunde.

Trade-off-ul ascuns din Prisma

Prisma e genială pentru DX și rapiditate în dezvoltare, dar când vine vorba de debugging pe conexiuni și tranzacții complexe, e o gaură neagră. Motorul lor scris în Rust ascunde prea multe detalii de implementare și nu știi niciodată exact ce se întâmplă la nivel de protocol de Postgres în momentele de load.

Folosim PgBouncer în fața bazei de date, configurat pe mod session. Am citit pe diverse thread-uri de GitHub că Prisma nu se înțelege prea bine cu PgBouncer în mod transaction, dar noi fiind pe session teoretic ar trebui să fie safe. Totuși, am un feeling puternic că acolo e buba. Dacă dezactivăm PgBouncer, riscăm să epuizăm conexiunile fizice în orele de vârf, deci e un trade-off destul de periculos pe care nu l-aș face direct în producție fără să fiu sigur.

A mai lovit cineva ciudățenia asta în producție? Există vreo setare ascunsă de PgBouncer sau vreo limitare de conexiuni în Prisma Client pe care am ratat-o? Orice idee e binevenită, că deja clienții încep să vadă prea multe erori 500 la checkout.

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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