Skip to content

Commit 7b00d0f

Browse files
authored
fix(NODE-3711): retry txn end on retryable write (#3045)
1 parent c2a10b4 commit 7b00d0f

File tree

4 files changed

+36
-8
lines changed

4 files changed

+36
-8
lines changed

src/error.ts

+4
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,10 @@ const RETRYABLE_WRITE_ERROR_CODES = new Set<number>([
697697
MONGODB_ERROR_CODES.ExceededTimeLimit
698698
]);
699699

700+
export function isRetryableEndTransactionError(error: MongoError): boolean {
701+
return error.hasErrorLabel('RetryableWriteError');
702+
}
703+
700704
export function isRetryableWriteError(error: MongoError): boolean {
701705
if (error instanceof MongoWriteConcernError) {
702706
return RETRYABLE_WRITE_ERROR_CODES.has(error.result?.code ?? error.code ?? 0);

src/sessions.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
MongoError,
99
MongoInvalidArgumentError,
1010
isRetryableError,
11+
isRetryableEndTransactionError,
1112
MongoCompatibilityError,
1213
MongoNetworkError,
1314
MongoWriteConcernError,
@@ -767,7 +768,7 @@ function endTransaction(session: ClientSession, commandName: string, callback: C
767768
session.unpin();
768769
}
769770

770-
if (err && isRetryableError(err as MongoError)) {
771+
if (err && isRetryableEndTransactionError(err as MongoError)) {
771772
// SPEC-1185: apply majority write concern when retrying commitTransaction
772773
if (command.commitTransaction) {
773774
// per txns spec, must unpin session in this case

test/functional/transactions.test.js

+1-7
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,7 @@ const SKIP_TESTS = [
111111

112112
// Will be implemented as part of NODE-2034
113113
'Client side error in command starting transaction',
114-
'Client side error when transaction is in progress',
115-
116-
// Will be implemented as part of NODE-2538
117-
'abortTransaction only retries once with RetryableWriteError from server',
118-
'abortTransaction does not retry without RetryableWriteError label',
119-
'commitTransaction does not retry error without RetryableWriteError label',
120-
'commitTransaction retries once with RetryableWriteError from server'
114+
'Client side error when transaction is in progress'
121115
];
122116

123117
describe('Transactions Spec Legacy Tests', function () {

test/unit/error.test.js

+29
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const { ReplSetFixture } = require('../tools/common');
88
const { ns } = require('../../src/utils');
99
const { Topology } = require('../../src/sdam/topology');
1010
const { MongoNetworkError, MongoWriteConcernError } = require('../../src/index');
11+
const { isRetryableEndTransactionError } = require('../../src/error');
1112
const {
1213
PoolClosedError: MongoPoolClosedError,
1314
WaitQueueTimeoutError: MongoWaitQueueTimeoutError
@@ -36,6 +37,34 @@ describe('MongoErrors', () => {
3637
});
3738
}
3839

40+
describe('#isRetryableEndTransactionError', function () {
41+
context('when the error has a RetryableWriteError label', function () {
42+
const error = new MongoNetworkError('');
43+
error.addErrorLabel('RetryableWriteError');
44+
45+
it('returns true', function () {
46+
expect(isRetryableEndTransactionError(error)).to.be.true;
47+
});
48+
});
49+
50+
context('when the error does not have a RetryableWriteError label', function () {
51+
const error = new MongoNetworkError('');
52+
error.addErrorLabel('InvalidLabel');
53+
54+
it('returns false', function () {
55+
expect(isRetryableEndTransactionError(error)).to.be.false;
56+
});
57+
});
58+
59+
context('when the error does not have any label', function () {
60+
const error = new MongoNetworkError('');
61+
62+
it('returns false', function () {
63+
expect(isRetryableEndTransactionError(error)).to.be.false;
64+
});
65+
});
66+
});
67+
3968
describe('when MongoNetworkError is constructed', () => {
4069
it('should only define beforeHandshake symbol if boolean option passed in', function () {
4170
const errorWithOptionTrue = new MongoNetworkError('', { beforeHandshake: true });

0 commit comments

Comments
 (0)