Skip to content

Commit

Permalink
fix(NODE-6436): only force majority write concern on commitTransactio…
Browse files Browse the repository at this point in the history
…n retry (#4284)
  • Loading branch information
W-A-James authored Oct 17, 2024
1 parent 3d5bd51 commit a7d1d43
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 3 deletions.
18 changes: 16 additions & 2 deletions src/sessions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ export class ClientSession
owner?: symbol | AbstractCursor;
defaultTransactionOptions: TransactionOptions;
transaction: Transaction;
/** @internal
* Keeps track of whether or not the current transaction has attempted to be committed. Is
* initially undefined. Gets set to false when startTransaction is called. When commitTransaction is sent to server, if the commitTransaction succeeds, it is then set to undefined, otherwise, set to true */
commitAttempted?: boolean;
/** @internal */
[kServerSession]: ServerSession | null;
/** @internal */
Expand Down Expand Up @@ -417,6 +421,7 @@ export class ClientSession
);
}

this.commitAttempted = false;
// increment txnNumber
this.incrementTransactionNumber();
// create transaction state
Expand Down Expand Up @@ -474,7 +479,7 @@ export class ClientSession
WriteConcern.apply(command, { wtimeoutMS: 10000, w: 'majority', ...wc });
}

if (this.transaction.state === TxnState.TRANSACTION_COMMITTED) {
if (this.transaction.state === TxnState.TRANSACTION_COMMITTED || this.commitAttempted) {
WriteConcern.apply(command, { wtimeoutMS: 10000, ...wc, w: 'majority' });
}

Expand All @@ -494,16 +499,25 @@ export class ClientSession

try {
await executeOperation(this.client, operation);
this.commitAttempted = undefined;
return;
} catch (firstCommitError) {
this.commitAttempted = true;
if (firstCommitError instanceof MongoError && isRetryableWriteError(firstCommitError)) {
// SPEC-1185: apply majority write concern when retrying commitTransaction
WriteConcern.apply(command, { wtimeoutMS: 10000, ...wc, w: 'majority' });
// per txns spec, must unpin session in this case
this.unpin({ force: true });

try {
await executeOperation(this.client, operation);
await executeOperation(
this.client,
new RunAdminCommandOperation(command, {
session: this,
readPreference: ReadPreference.primary,
bypassPinningCheck: true
})
);
return;
} catch (retryCommitError) {
// If the retry failed, we process that error instead of the original
Expand Down
32 changes: 31 additions & 1 deletion test/integration/transactions/transactions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { expect } from 'chai';
import {
ClientSession,
type Collection,
type CommandStartedEvent,
type MongoClient,
MongoInvalidArgumentError,
MongoNetworkError,
Expand Down Expand Up @@ -231,8 +232,13 @@ describe('Transactions', function () {

context('when completing a transaction', () => {
let client: MongoClient;
let commandsStarted: CommandStartedEvent[];
beforeEach(async function () {
client = this.configuration.newClient();
client = this.configuration.newClient(undefined, { monitorCommands: true });
commandsStarted = [];
client.on('commandStarted', ev => {
commandsStarted.push(ev);
});
});

afterEach(async function () {
Expand Down Expand Up @@ -260,6 +266,30 @@ describe('Transactions', function () {
})
)
);

it(
'commitTransaction does not override write concern on initial attempt',
{ requires: { mongodb: '>=4.2.0', topology: '!single' } },
async function () {
await client
.db('test')
.dropCollection('test')
.catch(() => null);
const collection = await client.db('test').createCollection('test');
const session = client.startSession({
defaultTransactionOptions: { writeConcern: { w: 1 } }
});
session.startTransaction();
await collection.insertOne({ x: 1 }, { session });
await session.commitTransaction();

const commitTransactions = commandsStarted.filter(
x => x.commandName === 'commitTransaction'
);
expect(commitTransactions).to.have.lengthOf(1);
expect(commitTransactions[0].command).to.have.nested.property('writeConcern.w', 1);
}
);
});

describe('TransientTransactionError', function () {
Expand Down

0 comments on commit a7d1d43

Please sign in to comment.