Skip to content

Commit 56ae0ad

Browse files
committed
1 parent c3c82b6 commit 56ae0ad

2 files changed

Lines changed: 29 additions & 20 deletions

File tree

source/transactions-convenient-api/tests/README.md

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,23 +29,20 @@ Write a callback that returns a custom value (e.g. boolean, string, object). Exe
2929
Drivers should test that `withTransaction` enforces a non-configurable timeout before retrying both commits and entire
3030
transactions. Specifically, three cases should be checked:
3131

32-
- If the callback raises an error with the TransientTransactionError label and the retry timeout has been exceeded,
33-
`withTransaction` should propagate the error (see Note 1 below) to its caller.
32+
- If the callback raises an error with the `TransientTransactionError` label and the retry timeout has been exceeded,
33+
`withTransaction` should propagate the error as described in the [propagation mechanism](../transactions-convenient-api.md#timeout-error-propagation-mechanism) below) to its caller.
3434
- If committing raises an error with the UnknownTransactionCommitResult label, and the retry timeout has been exceeded,
35-
`withTransaction` should propagate the error (see Note 1 below) to its caller.
35+
`withTransaction` should propagate the error as described in the [propagation mechanism](../transactions-convenient-api.md#timeout-error-propagation-mechanism) to its caller.
3636
- If committing raises an error with the TransientTransactionError label and the retry timeout has been exceeded,
37-
`withTransaction` should propagate the error (see Note 1 below) to its caller. This case may occur if the commit was
38-
internally retried against a new primary after a failover and the second primary returned a NoSuchTransaction error
37+
`withTransaction` should propagate the error as described in the [propagation mechanism](../transactions-convenient-api.md#timeout-error-propagation-mechanism) to its caller. This case may occur if the commit was
38+
internally retried against a new primary after a failover and the second primary returned a `NoSuchTransaction` error
3939
response.
4040

4141
If possible, drivers should implement these tests without requiring the test runner to block for the full duration of
4242
the retry timeout. This might be done by internally modifying the timeout value used by `withTransaction` with some
4343
private API or using a mock timer.
4444

45-
______________________________________________________________________
46-
47-
**Note 1:** The error SHOULD be propagated as a timeout error if the language allows to expose the underlying error as a
48-
cause of a timeout error.
45+
The drivers should assert that the timeout error propagated has the same labels as the error it wraps.
4946

5047
### Retry Backoff is Enforced
5148

source/transactions-convenient-api/transactions-convenient-api.md

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ This method should perform the following sequence of actions:
123123

124124
2. If `transactionAttempt` > 0:
125125

126-
1. If elapsed time + `backoffMS` > `TIMEOUT_MS`, then raise the previously encountered error (see Note 1 below). If
126+
1. If elapsed time + `backoffMS` > `TIMEOUT_MS`, then propagate the previously encountered error (see [propagation section](transactions-convenient-api.md#timeout-error-propagation-mechanism) below). If
127127
the elapsed time of `withTransaction` is less than TIMEOUT_MS, calculate the backoffMS to be
128128
`jitter * min(BACKOFF_INITIAL * 1.5 ** (transactionAttempt - 1), BACKOFF_MAX)`. sleep for `backoffMS`.
129129

@@ -163,7 +163,7 @@ This method should perform the following sequence of actions:
163163
committed a transaction, propagate the callback's error to the caller of `withTransaction` and return
164164
immediately.
165165

166-
4. Otherwise, propagate the callback's error (see Note 1 below) to the caller of `withTransaction` and return
166+
4. Otherwise, propagate the callback's error (see [propagation section](transactions-convenient-api.md#timeout-error-propagation-mechanism) below) to the caller of `withTransaction` and return
167167
immediately.
168168

169169
8. If the ClientSession is in the "no transaction", "transaction aborted", or "transaction committed" state, assume the
@@ -180,20 +180,19 @@ This method should perform the following sequence of actions:
180180

181181
2. If the `commitTransaction` error includes a "TransientTransactionError" label, jump back to step two.
182182

183-
3. Otherwise, propagate the `commitTransaction` error (see Note 1 below) to the caller of `withTransaction` and
183+
3. Otherwise, propagate the `commitTransaction` error (see [propagation section](transactions-convenient-api.md#timeout-error-propagation-mechanism) below) to the caller of `withTransaction` and
184184
return immediately.
185185

186186
11. The transaction was committed successfully. Return immediately.
187187

188-
______________________________________________________________________
189-
190-
**Note 1:** When the `TIMEOUT_MS` (calculated in step [1.3](#sequence-of-actions)) is reached we MUST report a timeout
191-
error wrapping the last error that was encountered which triggered the retry behavior. If `timeoutMS` is set, then
188+
###### Timeout Error propagation mechanism
189+
When the `TIMEOUT_MS` (calculated in step [1.3](#sequence-of-actions)) is reached we MUST report a timeout
190+
error wrapping the previously encountered error. If `timeoutMS` is set, then
192191
timeout error is a special type which is defined in CSOT
193192
[specification](https://github.com/mongodb/specifications/blob/master/source/client-side-operations-timeout/client-side-operations-timeout.md#errors)
194-
, If `timeoutMS` is not set, then propagate it as timeout error if the language allows to expose the underlying error as
193+
, If `timeoutMS` is not set, then propagate it as timeout error if the language allows to expose the previously encountered error as
195194
a cause of a timeout error (see `makeTimeoutError` below in [pseudo-code](#pseudo-code)). If timeout error is thrown
196-
then it SHOULD expose error label(s) from the transient error.
195+
then it SHOULD copy all error label(s) from the previously encountered error.
197196

198197
##### Pseudo-code
199198

@@ -228,11 +227,13 @@ withTransaction(callback, options) {
228227
callback(this);
229228
} catch (error) {
230229
lastError = error;
230+
// step 7.1
231231
if (this.transactionState == STARTING ||
232232
this.transactionState == IN_PROGRESS) {
233233
this.abortTransaction();
234234
}
235235

236+
// step 7.2
236237
if (error.hasErrorLabel("TransientTransactionError")) {
237238
if (Date.now() - startTime < timeout) {
238239
continue retryTransaction;
@@ -241,9 +242,16 @@ withTransaction(callback, options) {
241242
}
242243
}
243244

244-
throw error;
245+
// step 7.3
246+
if (error.hasErrorLabel("UnknownTransactionCommitResult")) {
247+
throw error;
248+
}
249+
250+
// step 7.4
251+
throw makeTimeoutError(error);
245252
}
246253

254+
// step 8
247255
if (this.transactionState == NO_TXN ||
248256
this.transactionState == COMMITTED ||
249257
this.transactionState == ABORTED) {
@@ -252,6 +260,7 @@ withTransaction(callback, options) {
252260

253261
retryCommit: while (true) {
254262
try {
263+
// step 9
255264
/* We will rely on ClientSession.commitTransaction() to
256265
* apply a majority write concern if commitTransaction is
257266
* being retried (see: DRIVERS-601) */
@@ -267,15 +276,18 @@ withTransaction(callback, options) {
267276
if (Date.now() - startTime >= timeout) {
268277
throw makeTimeoutError(error);
269278
}
279+
// step 10.1
270280
if (!isMaxTimeMSExpiredError(error) &&
271281
error.hasErrorLabel("UnknownTransactionCommitResult")) {
272282
continue retryCommit;
273283
}
274284

285+
// step 10.2
275286
if (error.hasErrorLabel("TransientTransactionError")) {
276287
continue retryTransaction;
277288
}
278289

290+
// step 10.3
279291
throw error;
280292
}
281293
break; // Commit was successful
@@ -348,7 +360,7 @@ An earlier design also considered using the callback's return value to indicate
348360
of two ways:
349361

350362
- The callback aborts the transaction directly and returns to `withTransaction`, which will then return to its caller.
351-
- The callback raises an error without the "TransientTransactionError" label, in which case `withTransaction` will abort
363+
- The callback propagates an error without the "TransientTransactionError" label, in which case `withTransaction` will abort
352364
the transaction and return to its caller.
353365

354366
### Applications are responsible for passing ClientSession for operations within a transaction

0 commit comments

Comments
 (0)