Skip to content
This repository has been archived by the owner on Feb 4, 2022. It is now read-only.

Commit

Permalink
feat(retryable-writes): retry on "not master" stepdown errors
Browse files Browse the repository at this point in the history
NODE-1105
  • Loading branch information
mbroadst committed Dec 1, 2017
1 parent 5762f6c commit 028aec7
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 2 deletions.
2 changes: 1 addition & 1 deletion lib/topologies/mongos.js
Original file line number Diff line number Diff line change
Expand Up @@ -900,7 +900,7 @@ var executeWriteOperation = function(self, op, ns, ops, options, callback) {

server[op](ns, ops, options, (err, result) => {
if (!err) return callback(null, result);
if (!(err instanceof errors.MongoNetworkError)) {
if (!(err instanceof errors.MongoNetworkError) && !err.message.match(/not master/)) {
return callback(err);
}

Expand Down
2 changes: 1 addition & 1 deletion lib/topologies/replset.js
Original file line number Diff line number Diff line change
Expand Up @@ -1187,7 +1187,7 @@ var executeWriteOperation = function(self, op, ns, ops, options, callback) {

self.s.replicaSetState.primary[op](ns, ops, options, (err, result) => {
if (!err) return callback(null, result);
if (!(err instanceof errors.MongoNetworkError)) {
if (!(err instanceof errors.MongoNetworkError) && !err.message.match(/not master/)) {
return callback(err);
}

Expand Down
54 changes: 54 additions & 0 deletions test/tests/unit/mongos/retryable_writes_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,58 @@ describe('Retryable Writes (Mongos)', function() {
mongos.connect();
}
});

it('should retry write commands where `retryWrites` is true, and there is a "not master" error', {
metadata: { requires: { topology: ['single'] } },
test: function(done) {
const mongos = new Mongos(test.servers.map(server => server.address()), {
connectionTimeout: 3000,
socketTimeout: 0,
haInterval: 10000,
localThresholdMS: 500,
size: 1
});

const sessionPool = new ServerSessionPool(mongos);
const session = new ClientSession(mongos, sessionPool);

let command = null,
insertCount = 0;

const messageHandler = () => {
return request => {
const doc = request.document;
if (doc.ismaster) {
request.reply(test.defaultFields);
} else if (doc.insert) {
insertCount++;
if (insertCount === 1) {
request.reply({ ok: 0, errmsg: 'not master' }); // simulate a stepdown
} else {
command = doc;
request.reply({ ok: 1 });
}
}
};
};

test.servers[0].setMessageHandler(messageHandler('MONGOS1'));
test.servers[1].setMessageHandler(messageHandler('MONGOS2'));
mongos.once('fullsetup', function() {
mongos.insert('test.test', [{ a: 1 }], { retryWrites: true, session: session }, function(
err
) {
expect(err).to.not.exist;
expect(command).to.have.property('txnNumber');
expect(command.txnNumber).to.eql(1);

mongos.destroy();
done();
});
});

mongos.on('error', done);
mongos.connect();
}
});
});
54 changes: 54 additions & 0 deletions test/tests/unit/replset/retryable_writes_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,58 @@ describe('Retryable Writes (ReplSet)', function() {
replset.connect();
}
});

it('should retry write commands where `retryWrites` is true, and there is a "not master" error', {
metadata: { requires: { topology: ['single'] } },
test: function(done) {
var replset = new ReplSet(
[test.primaryServer.address(), test.firstSecondaryServer.address()],
{
setName: 'rs',
connectionTimeout: 100,
socketTimeout: 0,
haInterval: 100,
size: 5,
minSize: 1
}
);

const sessionPool = new ServerSessionPool(replset);
const session = new ClientSession(replset, sessionPool);

let command = null,
insertCount = 0;

test.primaryServer.setMessageHandler(request => {
const doc = request.document;
if (doc.ismaster) {
request.reply(test.primaryStates[0]);
} else if (doc.insert) {
insertCount++;
if (insertCount === 1) {
request.reply({ ok: 0, errmsg: 'not master' }); // simulate a stepdown
} else {
command = doc;
request.reply({ ok: 1 });
}
}
});

replset.on('all', () => {
replset.insert('test.test', [{ a: 1 }], { retryWrites: true, session: session }, function(
err
) {
expect(err).to.not.exist;
expect(command).to.have.property('txnNumber');
expect(command.txnNumber).to.eql(1);

replset.destroy();
done();
});
});

replset.on('error', done);
replset.connect();
}
});
});

0 comments on commit 028aec7

Please sign in to comment.