Skip to content

Commit 744741e

Browse files
update with comments
1 parent b508f8d commit 744741e

1 file changed

Lines changed: 33 additions & 20 deletions

File tree

src/sessions.ts

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -740,17 +740,30 @@ export class ClientSession
740740

741741
try {
742742
retryTransaction: for (
743-
let attempt = 0, isRetry = false;
743+
// 2. Set `transactionAttempt` to `0`.
744+
let transactionAttempt = 0, isRetry = false;
744745
!committed;
745-
++attempt, isRetry = attempt > 0
746+
++transactionAttempt, isRetry = transactionAttempt > 0
746747
) {
748+
// 2. If `transactionAttempt` > 0:
747749
if (isRetry) {
750+
// 2.i If elapsed time + `backoffMS` > `TIMEOUT_MS`, then raise the previously encountered error. If the elapsed time of
751+
// `withTransaction` is less than TIMEOUT_MS, calculate the backoffMS to be
752+
// `jitter * min(BACKOFF_INITIAL * 1.5 ** (transactionAttempt - 1), BACKOFF_MAX)`. sleep for `backoffMS`.
753+
// 2.i.i jitter is a random float between \[0, 1)
754+
// 2.i.ii `transactionAttempt` is the variable defined in step 1.
755+
// 2.i.iii `BACKOFF_INITIAL` is 5ms
756+
// 2.i.iv `BACKOFF_MAX` is 500ms
748757
const BACKOFF_INITIAL_MS = 5;
749758
const BACKOFF_MAX_MS = 500;
750759
const BACKOFF_GROWTH = 1.5;
751760
const jitter = Math.random();
752761
const backoffMS =
753-
jitter * Math.min(BACKOFF_INITIAL_MS * BACKOFF_GROWTH ** attempt, BACKOFF_MAX_MS);
762+
jitter *
763+
Math.min(
764+
BACKOFF_INITIAL_MS * BACKOFF_GROWTH ** (transactionAttempt - 1),
765+
BACKOFF_MAX_MS
766+
);
754767

755768
const willExceedTransactionDeadline =
756769
(this.timeoutContext?.csotEnabled() &&
@@ -769,13 +782,13 @@ export class ClientSession
769782
await setTimeout(backoffMS);
770783
}
771784

772-
// 2. Invoke startTransaction on the session
773-
// 3. If `startTransaction` reported an error, propagate that error to the caller of `withTransaction` and return immediately.
785+
// 3. Invoke startTransaction on the session
786+
// 4. If `startTransaction` reported an error, propagate that error to the caller of `withTransaction` and return immediately.
774787
this.startTransaction(options); // may throw on error
775788

776789
try {
777-
// 4. Invoke the callback.
778-
// 5. Control returns to withTransaction. (continued below)
790+
// 5. Invoke the callback.
791+
// 6. Control returns to withTransaction. (continued below)
779792
const promise = fn(this);
780793
if (!isPromiseLike(promise)) {
781794
throw new MongoInvalidArgumentError(
@@ -785,18 +798,18 @@ export class ClientSession
785798

786799
result = await promise;
787800

788-
// 5. (cont.) Determine the current state of the ClientSession (continued below)
801+
// 6. (cont.) Determine the current state of the ClientSession (continued below)
789802
if (
790803
this.transaction.state === TxnState.NO_TRANSACTION ||
791804
this.transaction.state === TxnState.TRANSACTION_COMMITTED ||
792805
this.transaction.state === TxnState.TRANSACTION_ABORTED
793806
) {
794-
// 7. If the ClientSession is in the "no transaction", "transaction aborted", or "transaction committed" state,
807+
// 8. If the ClientSession is in the "no transaction", "transaction aborted", or "transaction committed" state,
795808
// assume the callback intentionally aborted or committed the transaction and return immediately.
796809
return result;
797810
}
798811
// 5. (cont.) and whether the callback reported an error
799-
// 6. If the callback reported an error:
812+
// 7. If the callback reported an error:
800813
} catch (fnError) {
801814
if (!(fnError instanceof MongoError) || fnError instanceof MongoInvalidArgumentError) {
802815
// This first preemptive abort regardless of TxnState isn't spec,
@@ -809,7 +822,7 @@ export class ClientSession
809822
this.transaction.state === TxnState.STARTING_TRANSACTION ||
810823
this.transaction.state === TxnState.TRANSACTION_IN_PROGRESS
811824
) {
812-
// 6.i If the ClientSession is in the "starting transaction" or "transaction in progress" state,
825+
// 7.i If the ClientSession is in the "starting transaction" or "transaction in progress" state,
813826
// invoke abortTransaction on the session
814827
await this.abortTransaction();
815828
}
@@ -818,16 +831,16 @@ export class ClientSession
818831
fnError.hasErrorLabel(MongoErrorLabel.TransientTransactionError) &&
819832
(this.timeoutContext?.csotEnabled() || processTimeMS() - startTime < MAX_TIMEOUT)
820833
) {
821-
// 6.ii If the callback's error includes a "TransientTransactionError" label and the elapsed time of `withTransaction`
834+
// 7.ii If the callback's error includes a "TransientTransactionError" label and the elapsed time of `withTransaction`
822835
// is less than 120 seconds, jump back to step two.
823836
lastError = fnError;
824837
continue retryTransaction;
825838
}
826839

827-
// 6.iii If the callback's error includes a "UnknownTransactionCommitResult" label, the callback must have manually committed a transaction,
840+
// 7.iii If the callback's error includes a "UnknownTransactionCommitResult" label, the callback must have manually committed a transaction,
828841
// propagate the callback's error to the caller of withTransaction and return immediately.
829-
// The 6.iii check is redundant with 6.iv, so we don't write code for it
830-
// 6.iv Otherwise, propagate the callback's error to the caller of withTransaction and return immediately.
842+
// The 7.iii check is redundant with 6.iv, so we don't write code for it
843+
// 7.iv Otherwise, propagate the callback's error to the caller of withTransaction and return immediately.
831844
throw fnError;
832845
}
833846

@@ -838,10 +851,10 @@ export class ClientSession
838851
* apply a majority write concern if commitTransaction is
839852
* being retried (see: DRIVERS-601)
840853
*/
841-
// 8. Invoke commitTransaction on the session.
854+
// 9. Invoke commitTransaction on the session.
842855
await this.commitTransaction();
843856
committed = true;
844-
// 9. If commitTransaction reported an error:
857+
// 10. If commitTransaction reported an error:
845858
} catch (commitError) {
846859
// If CSOT is enabled, we repeatedly retry until timeoutMS expires. This is enforced by providing a
847860
// timeoutContext to each async API, which know how to cancel themselves (i.e., the next retry will
@@ -862,21 +875,21 @@ export class ClientSession
862875
!isMaxTimeMSExpiredError(commitError) &&
863876
commitError.hasErrorLabel(MongoErrorLabel.UnknownTransactionCommitResult)
864877
) {
865-
// 9.i If the `commitTransaction` error includes a "UnknownTransactionCommitResult" label and the error is not
878+
// 10.i If the `commitTransaction` error includes a "UnknownTransactionCommitResult" label and the error is not
866879
// MaxTimeMSExpired and the elapsed time of `withTransaction` is less than 120 seconds, jump back to step eight.
867880
continue retryCommit;
868881
}
869882

870883
if (commitError.hasErrorLabel(MongoErrorLabel.TransientTransactionError)) {
871-
// 9.ii If the commitTransaction error includes a "TransientTransactionError" label
884+
// 10.ii If the commitTransaction error includes a "TransientTransactionError" label
872885
// and the elapsed time of withTransaction is less than 120 seconds, jump back to step two.
873886
lastError = commitError;
874887

875888
continue retryTransaction;
876889
}
877890
}
878891

879-
// 9.iii Otherwise, propagate the commitTransaction error to the caller of withTransaction and return immediately.
892+
// 10.iii Otherwise, propagate the commitTransaction error to the caller of withTransaction and return immediately.
880893
throw commitError;
881894
}
882895
}

0 commit comments

Comments
 (0)