eduardweb.
Ajutor & ÎntrebăriIntermediar#nodejs#prisma#postgresql#backend-ajutor

Mă lupt cu „Transaction already closed” în Prisma și nu-i dau de cap în producție

De Cristian Barbu, 25 apr. 2026 · 1 vizualizări · 2 like-uri

Postat acum 2 zile

Salutare tuturor. Vin către voi cu o problemă care îmi mănâncă zilele de vreo săptămână și simt că am epuizat toate variantele clasice de debugging. Avem un serviciu în Node.js care rulează pe un cluster de Kubernetes și folosim Prisma (v5.12 în momentul ăsta) pentru un API destul de solicitat, cam 15k useri activi zilnic. Totul merge „ceas” în 99% din timp, dar la orele de vârf, logurile din Sentry încep să se umple de eroarea asta: Transaction already closed: A query cannot be executed on a closed transaction.

Faza e că eroarea e complet nespecifică și apare în locuri diferite din cod, deși toate folosesc tranzacții interactive ($transaction). Am zis inițial că e o problemă de timeout, așa că am sărit direct la soluția evidentă: am mărit maxWait la 10 secunde și timeout la 20 de secunde. Teoretic, e enorm pentru ce facem noi acolo, dar am zis să eliminăm variabila asta. Surpriză: eroarea continuă să apară, uneori chiar și după doar 2-3 secunde de la inițierea tranzacției, deci clar nu atinge pragul de 20 de secunde setat de mine.

Am verificat infrastructura de bază de date. Rulăm pe un Postgres gestionat (RDS) și avem PGBouncer în față. Știu că Prisma și PGBouncer au o relație complicată, așa că m-am asigurat că suntem pe session mode, nu pe transaction mode, fix cum recomandă documentația lor oficială pentru a evita conflictele de stare între conexiuni. Am monitorizat și numărul de conexiuni active: stăm undeva la 40% din capacitate, deci nu pare să fie o problemă de sufocare la nivel de DB.

Ce am mai încercat și n-a mers:

  1. Am redus logica din interiorul tranzacțiilor la minimul necesar. Am mutat orice calcul greu sau apel de API extern în afara blocului $transaction. Am crezut că poate blocăm event loop-ul și Prisma crede că tranzacția a expirat, dar n-a ajutat cu nimic.
  2. Am verificat versiunea de Node.js. Suntem pe 20.x (LTS), am făcut update de la 18 crezând că e ceva legat de garbage collection sau gestionarea resurselor, dar nicio schimbare.
  3. Am încercat să reproduc eroarea local cu un script de load testing (k6). Am tras în el cu 100 de request-uri pe secundă timp de 10 minute. Local? Totul e verde. În producție? Crapă la 5 request-uri pe secundă dacă e „momentul nepotrivit”.

Trade-off-ul la care mă gândesc acum e destul de dureros: să renunț la tranzacțiile interactive și să trec pe tranzacții secvențiale (cele cu array) acolo unde pot. Dar am multă logică condițională care depinde de rezultatul primului query pentru a decide ce face al doilea, deci refactorizarea ar fi un coșmar și ar introduce riscuri de consistență a datelor.

Am o bănuială că ar putea fi ceva legat de modul în care Prisma Engine (partea aia de Rust care rulează sub capotă) gestionează conexiunile când există un mic spike de latență în rețea între pod-ul de Kubernetes și baza de date. Dacă conexiunea TCP pică fie și pentru 50ms, Prisma pare să închidă tranzacția intern, dar codul meu de TypeScript încearcă să mai ruleze un await pe ea și primește eroarea în freză.

Ați pățit așa ceva pe proiecte mai mari? Există vreo setare de engine sau vreun flag obscur de care nu știu? Momentan singura mea „soluție” e un mecanism de retry cu exponential backoff, dar mi se pare un workaround mizerabil pentru o problemă care n-ar trebui să existe.

Voi cum monitorizați sănătatea tranzacțiilor în Prisma dincolo de log-urile standard?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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