@@ -84,7 +84,10 @@ export interface RunOpsCapableClient {
8484 * per-call `tx` so they share one transaction (see `runInTransaction`).
8585 */
8686export interface RunOpsTransactionalClient extends RunOpsCapableClient {
87- $transaction : < R > ( fn : ( tx : RunOpsCapableClient ) => Promise < R > ) => Promise < R > ;
87+ $transaction : < R > (
88+ fn : ( tx : RunOpsCapableClient ) => Promise < R > ,
89+ options ?: { timeout ?: number ; maxWait ?: number ; isolationLevel ?: unknown }
90+ ) => Promise < R > ;
8891}
8992
9093/**
@@ -99,6 +102,8 @@ export type RunStoreSchemaVariant = "legacy" | "dedicated";
99102// (apps/webapp/app/presenters/v3/WaitpointPresenter.server.ts) — keep the values in sync.
100103export const CONNECTED_RUNS_LIMIT = 5 ;
101104
105+ export const RUN_OPS_WRITE_TX_TIMEOUT_MS = 15_000 ;
106+
102107export type PostgresRunStoreOptions = {
103108 prisma : RunOpsCapableClient ;
104109 readOnlyPrisma : RunOpsCapableClient ;
@@ -661,15 +666,17 @@ export class PostgresRunStore implements RunStore {
661666 // (snapshot + completed-waitpoints, run + associated-waitpoint) which must commit together.
662667 #withOptionalTransaction< R > (
663668 tx : PrismaClientOrTransaction | undefined ,
664- fn : ( client : PrismaClientOrTransaction ) => Promise < R >
669+ fn : ( client : PrismaClientOrTransaction ) => Promise < R > ,
670+ options ?: { timeout ?: number ; maxWait ?: number }
665671 ) : Promise < R > {
666672 const alreadyInTransaction =
667673 tx !== undefined && typeof ( tx as { $transaction ?: unknown } ) . $transaction !== "function" ;
668674 if ( alreadyInTransaction ) {
669675 return fn ( tx ) ;
670676 }
671- return ( this . prisma as RunOpsTransactionalClient ) . $transaction ( ( t ) =>
672- fn ( t as unknown as PrismaClientOrTransaction )
677+ return ( this . prisma as RunOpsTransactionalClient ) . $transaction (
678+ ( t ) => fn ( t as unknown as PrismaClientOrTransaction ) ,
679+ options
673680 ) ;
674681 }
675682
@@ -694,19 +701,31 @@ export class PostgresRunStore implements RunStore {
694701 } ;
695702
696703 if ( this . schemaVariant === "dedicated" ) {
697- // The run + its associated RUN-type waitpoint are two writes here (the legacy branch below nests
698- // them). Commit them together so a crash / lagging read never leaves a run without its waitpoint.
699- return this . #withOptionalTransaction( tx , async ( c ) => {
700- const run = ( await c . taskRun . create ( {
704+ if ( ! params . associatedWaitpoint ) {
705+ const run = ( await client . taskRun . create ( {
701706 data : {
702707 ...params . data ,
703708 executionSnapshots : { create : snapshotCreate } ,
704709 } ,
705710 } ) ) as TaskRun ;
711+ return { ...run , associatedWaitpoint : null } ;
712+ }
706713
707- const associatedWaitpoint = await this . #createAssociatedWaitpoint( c , run . id , params ) ;
708- return { ...run , associatedWaitpoint } ;
709- } ) ;
714+ return this . #withOptionalTransaction(
715+ tx ,
716+ async ( c ) => {
717+ const run = ( await c . taskRun . create ( {
718+ data : {
719+ ...params . data ,
720+ executionSnapshots : { create : snapshotCreate } ,
721+ } ,
722+ } ) ) as TaskRun ;
723+
724+ const associatedWaitpoint = await this . #createAssociatedWaitpoint( c , run . id , params ) ;
725+ return { ...run , associatedWaitpoint } ;
726+ } ,
727+ { timeout : RUN_OPS_WRITE_TX_TIMEOUT_MS }
728+ ) ;
710729 }
711730
712731 return client . taskRun . create ( {
@@ -784,15 +803,25 @@ export class PostgresRunStore implements RunStore {
784803 const client = tx ?? this . prisma ;
785804
786805 if ( this . schemaVariant === "dedicated" ) {
787- // Run + associated RUN-type waitpoint are two writes here; commit them together (see createRun).
788- return this . #withOptionalTransaction( tx , async ( c ) => {
789- const run = ( await c . taskRun . create ( {
806+ if ( ! params . associatedWaitpoint ) {
807+ const run = ( await client . taskRun . create ( {
790808 data : { ...params . data } ,
791809 } ) ) as TaskRun ;
810+ return { ...run , associatedWaitpoint : null } ;
811+ }
792812
793- const associatedWaitpoint = await this . #createAssociatedWaitpoint( c , run . id , params ) ;
794- return { ...run , associatedWaitpoint } ;
795- } ) ;
813+ return this . #withOptionalTransaction(
814+ tx ,
815+ async ( c ) => {
816+ const run = ( await c . taskRun . create ( {
817+ data : { ...params . data } ,
818+ } ) ) as TaskRun ;
819+
820+ const associatedWaitpoint = await this . #createAssociatedWaitpoint( c , run . id , params ) ;
821+ return { ...run , associatedWaitpoint } ;
822+ } ,
823+ { timeout : RUN_OPS_WRITE_TX_TIMEOUT_MS }
824+ ) ;
796825 }
797826
798827 return client . taskRun . create ( {
0 commit comments