Skip to content

Commit

Permalink
refactor: align isSDAMUnrecoverableError with spec guidance
Browse files Browse the repository at this point in the history
This makes the error checking for whether an error is an SDAM
unrecoverable error line up with the pseudocode in the SDAM
specification.
  • Loading branch information
mbroadst committed Aug 22, 2019
1 parent dd79a22 commit 5188bda
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 17 deletions.
52 changes: 43 additions & 9 deletions lib/core/error.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,28 +153,62 @@ function isRetryableError(error) {
);
}

const SDAM_UNRECOVERABLE_ERROR_CODES = new Set([
const SDAM_RECOVERING_CODES = new Set([
91, // ShutdownInProgress
189, // PrimarySteppedDown
10107, // NotMaster
11600, // InterruptedAtShutdown
11602, // InterruptedDueToReplStateChange
13435, // NotMasterNoSlaveOk
13436 // NotMasterOrSecondary
]);

const SDAM_NOTMASTER_CODES = new Set([
10107, // NotMaster
13435 // NotMasterNoSlaveOk
]);

const SDAM_NODE_SHUTTING_DOWN_ERROR_CODES = new Set([
11600, // InterruptedAtShutdown
91 // ShutdownInProgress
]);

function isRecoveringError(err) {
if (err.code && SDAM_RECOVERING_CODES.has(err.code)) {
return true;
}

return err.message.match(/not master or secondary/) || err.message.match(/node is recovering/);
}

function isNotMasterError(err) {
if (err.code && SDAM_NOTMASTER_CODES.has(err.code)) {
return true;
}

if (isRecoveringError(err)) {
return false;
}

return err.message.match(/not master/);
}

function isNodeShuttingDownError(err) {
return SDAM_NODE_SHUTTING_DOWN_ERROR_CODES.has(err.code);
}

/**
* Determines whether an error is a "node is recovering" error or
* a "not master" error for SDAM retryability.
* Determines whether SDAM can recover from a given error. If it cannot
* then the pool will be cleared, and server state will completely reset
* locally.
*
* @see https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-discovery-and-monitoring.rst#not-master-and-node-is-recovering
* @param {MongoError|Error} error
* @param {Server} server
*/
function isSDAMUnrecoverableError(error) {
function isSDAMUnrecoverableError(error, server) {
return (
SDAM_UNRECOVERABLE_ERROR_CODES.has(error.code) ||
(error.message &&
(error.message.match(/not master/) || error.message.match(/node is recovering/)))
error instanceof MongoParseError ||
((isRecoveringError(error) || isNotMasterError(error)) &&
(maxWireVersion(server) >= 8 && isNodeShuttingDownError(error)))
);
}

Expand Down
12 changes: 6 additions & 6 deletions lib/core/sdam/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ class Server extends EventEmitter {
options.session.serverSession.isDirty = true;
}

if (isSDAMUnrecoverableError(err)) {
if (isSDAMUnrecoverableError(err, this)) {
this.emit('error', err);
}
}
Expand All @@ -269,7 +269,7 @@ class Server extends EventEmitter {
options.session.serverSession.isDirty = true;
}

if (isSDAMUnrecoverableError(err)) {
if (isSDAMUnrecoverableError(err, this)) {
this.emit('error', err);
}
}
Expand All @@ -293,7 +293,7 @@ class Server extends EventEmitter {
options.session.serverSession.isDirty = true;
}

if (isSDAMUnrecoverableError(err)) {
if (isSDAMUnrecoverableError(err, this)) {
this.emit('error', err);
}
}
Expand All @@ -311,7 +311,7 @@ class Server extends EventEmitter {
*/
killCursors(ns, cursorState, callback) {
wireProtocol.killCursors(this, ns, cursorState, (err, result) => {
if (err && isSDAMUnrecoverableError(err)) {
if (err && isSDAMUnrecoverableError(err, this)) {
this.emit('error', err);
}

Expand Down Expand Up @@ -419,7 +419,7 @@ function executeWriteOperation(args, options, callback) {
}

if (collationNotSupported(server, options)) {
callback(new MongoError(`server ${this.name} does not support collation`));
callback(new MongoError(`server ${server.name} does not support collation`));
return;
}

Expand All @@ -429,7 +429,7 @@ function executeWriteOperation(args, options, callback) {
options.session.serverSession.isDirty = true;
}

if (isSDAMUnrecoverableError(err)) {
if (isSDAMUnrecoverableError(err, server)) {
server.emit('error', err);
}
}
Expand Down
3 changes: 1 addition & 2 deletions lib/core/sdam/topology.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ const deprecate = require('util').deprecate;
const BSON = require('../connection/utils').retrieveBSON();
const createCompressionInfo = require('../topologies/shared').createCompressionInfo;
const isRetryableError = require('../error').isRetryableError;
const MongoParseError = require('../error').MongoParseError;
const isSDAMUnrecoverableError = require('../error').isSDAMUnrecoverableError;
const ClientSession = require('../sessions').ClientSession;
const createClientInfo = require('../topologies/shared').createClientInfo;
Expand Down Expand Up @@ -938,7 +937,7 @@ function serverErrorEventHandler(server, topology) {
new monitoring.ServerClosedEvent(topology.s.id, server.description.address)
);

if (err instanceof MongoParseError || isSDAMUnrecoverableError(err)) {
if (isSDAMUnrecoverableError(err, server)) {
resetServerState(server, err, { clearPool: true });
return;
}
Expand Down

0 comments on commit 5188bda

Please sign in to comment.