@@ -129,11 +129,31 @@ export const runOpsLegacyTransactionResilience = resolveTransactionResilience("r
129129 budgetBurst : env . RUN_OPS_LEGACY_DATABASE_TRANSACTION_START_RETRY_BUDGET_BURST ,
130130} ) ;
131131
132- function withTransactionDefaults ( options ?: PrismaTransactionOptions ) : PrismaTransactionOptions {
132+ const transactionResilienceByClient = new WeakMap < object , TransactionResilienceConfig > ( ) ;
133+
134+ /**
135+ * Associates a writer client with its pool's resilience config so the `$transaction` helper can
136+ * pick the right `maxWait` + retry budget for whichever client it is handed, rather than always
137+ * using the control-plane pool. Returns the client for inline use at construction.
138+ */
139+ function registerTransactionResilience < T extends object > (
140+ client : T ,
141+ resilience : TransactionResilienceConfig
142+ ) : T {
143+ transactionResilienceByClient . set ( client , resilience ) ;
144+ return client ;
145+ }
146+
147+ function withTransactionDefaults (
148+ client : PrismaClientOrTransaction ,
149+ options ?: PrismaTransactionOptions
150+ ) : PrismaTransactionOptions {
151+ const resilience =
152+ transactionResilienceByClient . get ( client as object ) ?? controlPlaneTransactionResilience ;
133153 return {
134- maxWait : controlPlaneTransactionResilience . maxWait ,
154+ maxWait : resilience . maxWait ,
135155 ...options ,
136- startRetry : options ?. startRetry ?? controlPlaneTransactionResilience . startRetry ,
156+ startRetry : options ?. startRetry ?? resilience . startRetry ,
137157 } ;
138158}
139159
@@ -171,7 +191,7 @@ async function $transactionInner<R>(
171191 options ?: PrismaTransactionOptions
172192) : Promise < R | undefined > {
173193 if ( typeof fnOrName === "string" ) {
174- const effectiveOptions = withTransactionDefaults ( options ) ;
194+ const effectiveOptions = withTransactionDefaults ( prisma , options ) ;
175195 return await startActiveSpan ( fnOrName , async ( span ) => {
176196 span . setAttribute ( "$transaction" , true ) ;
177197
@@ -205,7 +225,7 @@ async function $transactionInner<R>(
205225 prisma ,
206226 fnOrName ,
207227 logTransactionPrismaError ,
208- withTransactionDefaults ( typeof fnOrOptions === "function" ? undefined : fnOrOptions )
228+ withTransactionDefaults ( prisma , typeof fnOrOptions === "function" ? undefined : fnOrOptions )
209229 ) ;
210230 }
211231}
@@ -264,7 +284,10 @@ function captureInfraErrorsRunOps(client: RunOpsPrismaClient): RunOpsPrismaClien
264284}
265285
266286export const prisma = singleton ( "prisma" , ( ) =>
267- captureInfrastructureErrors ( tagDatasource ( "control-plane-writer" , getClient ( ) ) )
287+ registerTransactionResilience (
288+ captureInfrastructureErrors ( tagDatasource ( "control-plane-writer" , getClient ( ) ) ) ,
289+ controlPlaneTransactionResilience
290+ )
268291) ;
269292
270293export const $replica : PrismaReplicaClient = singleton ( "replica" , ( ) => {
@@ -393,15 +416,18 @@ const runOpsTopology: RunOpsTopology = singleton("runOpsTopology", () => {
393416 {
394417 controlPlane : { writer : prisma , replica : $replica } ,
395418 buildNewWriter : ( url , clientType ) =>
396- captureInfraErrorsRunOps (
397- tagDatasourceRunOps (
398- "run-ops-writer" ,
399- buildRunOpsWriterClient ( {
400- url,
401- clientType,
402- useDriverAdapter : env . RUN_OPS_DATABASE_WRITER_DRIVER_ADAPTER === "1" ,
403- } )
404- )
419+ registerTransactionResilience (
420+ captureInfraErrorsRunOps (
421+ tagDatasourceRunOps (
422+ "run-ops-writer" ,
423+ buildRunOpsWriterClient ( {
424+ url,
425+ clientType,
426+ useDriverAdapter : env . RUN_OPS_DATABASE_WRITER_DRIVER_ADAPTER === "1" ,
427+ } )
428+ )
429+ ) ,
430+ runOpsTransactionResilience
405431 ) ,
406432 // Brand the run-ops replica (only built for a real replica URL) so routed replica reads stay
407433 // off the primary. When no replica URL is set, selectRunOpsTopology reuses the writer here —
@@ -422,17 +448,20 @@ const runOpsTopology: RunOpsTopology = singleton("runOpsTopology", () => {
422448 // Legacy client shares the exact control-plane wrapper stack (the legacy DB carries the full
423449 // control-plane schema); markReadReplicaClient only on a real replica URL, as with the NEW replica.
424450 buildLegacyWriter : ( url , clientType ) =>
425- captureInfrastructureErrors (
426- tagDatasource (
427- "legacy-run-ops-writer" ,
428- buildWriterClient ( {
429- url,
430- clientType,
431- poolTimeout : env . RUN_OPS_LEGACY_DATABASE_WRITER_POOL_TIMEOUT ,
432- connectTimeout : env . RUN_OPS_LEGACY_DATABASE_WRITER_CONNECTION_TIMEOUT ,
433- useDriverAdapter : env . RUN_OPS_LEGACY_DATABASE_WRITER_DRIVER_ADAPTER === "1" ,
434- } )
435- )
451+ registerTransactionResilience (
452+ captureInfrastructureErrors (
453+ tagDatasource (
454+ "legacy-run-ops-writer" ,
455+ buildWriterClient ( {
456+ url,
457+ clientType,
458+ poolTimeout : env . RUN_OPS_LEGACY_DATABASE_WRITER_POOL_TIMEOUT ,
459+ connectTimeout : env . RUN_OPS_LEGACY_DATABASE_WRITER_CONNECTION_TIMEOUT ,
460+ useDriverAdapter : env . RUN_OPS_LEGACY_DATABASE_WRITER_DRIVER_ADAPTER === "1" ,
461+ } )
462+ )
463+ ) ,
464+ runOpsLegacyTransactionResilience
436465 ) ,
437466 buildLegacyReplica : ( url , clientType ) =>
438467 markReadReplicaClient (
0 commit comments