1+ import { setTimeout } from 'timers/promises' ;
2+
13import { Binary , type Document , Long , type Timestamp } from './bson' ;
24import type { CommandOptions , Connection } from './cmap/connection' ;
35import { ConnectionPoolMetrics } from './cmap/metrics' ;
@@ -776,7 +778,7 @@ export class ClientSession
776778 throw fnError ;
777779 }
778780
779- while ( ! committed ) {
781+ for ( let retry = 0 ; ! committed ; ++ retry ) {
780782 try {
781783 /*
782784 * We will rely on ClientSession.commitTransaction() to
@@ -786,9 +788,23 @@ export class ClientSession
786788 await this . commitTransaction ( ) ;
787789 committed = true ;
788790 } catch ( commitError ) {
791+ const hasNotTimedOut =
792+ this . timeoutContext ?. csotEnabled ( ) || now ( ) - startTime < MAX_TIMEOUT ;
793+
794+ /**
795+ * will the provided backoffMS exceed the withTransaction's deadline?
796+ */
797+ const willExceedTransactionDeadline = ( backoffMS : number ) => {
798+ return (
799+ ( this . timeoutContext ?. csotEnabled ( ) &&
800+ backoffMS > this . timeoutContext . remainingTimeMS ) ||
801+ now ( ) + backoffMS > startTime + MAX_TIMEOUT
802+ ) ;
803+ } ;
804+
789805 // If CSOT is enabled, we repeatedly retry until timeoutMS expires.
790806 // If CSOT is not enabled, do we still have time remaining or have we timed out?
791- if ( this . timeoutContext ?. csotEnabled ( ) || now ( ) - startTime < MAX_TIMEOUT ) {
807+ if ( hasNotTimedOut ) {
792808 if (
793809 ! isMaxTimeMSExpiredError ( commitError ) &&
794810 commitError . hasErrorLabel ( MongoErrorLabel . UnknownTransactionCommitResult )
@@ -800,6 +816,19 @@ export class ClientSession
800816 * { ok:0, code: 50, codeName: 'MaxTimeMSExpired' }
801817 * { ok:1, writeConcernError: { code: 50, codeName: 'MaxTimeMSExpired' } }
802818 */
819+
820+ const BACKOFF_INITIAL_MS = 1 ;
821+ const BACKOFF_MAX_MS = 500 ;
822+ const jitter = Math . random ( ) ;
823+ const backoffMS =
824+ jitter * Math . min ( BACKOFF_INITIAL_MS * 1.25 ** retry , BACKOFF_MAX_MS ) ;
825+
826+ if ( willExceedTransactionDeadline ( backoffMS ) ) {
827+ break ;
828+ }
829+
830+ await setTimeout ( backoffMS ) ;
831+
803832 continue ;
804833 }
805834
0 commit comments