Skip to content

Commit 47c7893

Browse files
authored
refactor(NODE-3788): update names of offensive error codes (#3063)
* Update references to master in error.ts * fix test that checks error message * Use original error messages & abstract to constants * Add unit tests for isSDAMUnrecoverableError * Add comments * Code review: create constants
1 parent bcc57d6 commit 47c7893

File tree

2 files changed

+135
-24
lines changed

2 files changed

+135
-24
lines changed

src/error.ts

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,27 @@ export type AnyError = MongoError | Error;
88
/** @internal */
99
const kErrorLabels = Symbol('errorLabels');
1010

11+
/**
12+
* @internal
13+
* The legacy error message from the server that indicates the node is not a writable primary
14+
* https://github.com/mongodb/specifications/blob/b07c26dc40d04ac20349f989db531c9845fdd755/source/server-discovery-and-monitoring/server-discovery-and-monitoring.rst#not-writable-primary-and-node-is-recovering
15+
*/
16+
export const LEGACY_NOT_WRITABLE_PRIMARY_ERROR_MESSAGE = 'not master';
17+
18+
/**
19+
* @internal
20+
* The legacy error message from the server that indicates the node is not a primary or secondary
21+
* https://github.com/mongodb/specifications/blob/b07c26dc40d04ac20349f989db531c9845fdd755/source/server-discovery-and-monitoring/server-discovery-and-monitoring.rst#not-writable-primary-and-node-is-recovering
22+
*/
23+
export const LEGACY_NOT_PRIMARY_OR_SECONDARY_ERROR_MESSAGE = 'not master or secondary';
24+
25+
/**
26+
* @internal
27+
* The error message from the server that indicates the node is recovering
28+
* https://github.com/mongodb/specifications/blob/b07c26dc40d04ac20349f989db531c9845fdd755/source/server-discovery-and-monitoring/server-discovery-and-monitoring.rst#not-writable-primary-and-node-is-recovering
29+
*/
30+
export const NODE_IS_RECOVERING_ERROR_MESSAGE = 'node is recovering';
31+
1132
/** @internal MongoDB Error Codes */
1233
export const MONGODB_ERROR_CODES = Object.freeze({
1334
HostUnreachable: 6,
@@ -17,11 +38,11 @@ export const MONGODB_ERROR_CODES = Object.freeze({
1738
PrimarySteppedDown: 189,
1839
ExceededTimeLimit: 262,
1940
SocketException: 9001,
20-
NotMaster: 10107,
41+
NotWritablePrimary: 10107,
2142
InterruptedAtShutdown: 11600,
2243
InterruptedDueToReplStateChange: 11602,
23-
NotMasterNoSlaveOk: 13435,
24-
NotMasterOrSecondary: 13436,
44+
NotPrimaryNoSecondaryOk: 13435,
45+
NotPrimaryOrSecondary: 13436,
2546
StaleShardVersion: 63,
2647
StaleEpoch: 150,
2748
StaleConfig: 13388,
@@ -46,11 +67,11 @@ export const GET_MORE_RESUMABLE_CODES = new Set<number>([
4667
MONGODB_ERROR_CODES.PrimarySteppedDown,
4768
MONGODB_ERROR_CODES.ExceededTimeLimit,
4869
MONGODB_ERROR_CODES.SocketException,
49-
MONGODB_ERROR_CODES.NotMaster,
70+
MONGODB_ERROR_CODES.NotWritablePrimary,
5071
MONGODB_ERROR_CODES.InterruptedAtShutdown,
5172
MONGODB_ERROR_CODES.InterruptedDueToReplStateChange,
52-
MONGODB_ERROR_CODES.NotMasterNoSlaveOk,
53-
MONGODB_ERROR_CODES.NotMasterOrSecondary,
73+
MONGODB_ERROR_CODES.NotPrimaryNoSecondaryOk,
74+
MONGODB_ERROR_CODES.NotPrimaryOrSecondary,
5475
MONGODB_ERROR_CODES.StaleShardVersion,
5576
MONGODB_ERROR_CODES.StaleEpoch,
5677
MONGODB_ERROR_CODES.StaleConfig,
@@ -675,19 +696,19 @@ const RETRYABLE_ERROR_CODES = new Set<number>([
675696
MONGODB_ERROR_CODES.ShutdownInProgress,
676697
MONGODB_ERROR_CODES.PrimarySteppedDown,
677698
MONGODB_ERROR_CODES.SocketException,
678-
MONGODB_ERROR_CODES.NotMaster,
699+
MONGODB_ERROR_CODES.NotWritablePrimary,
679700
MONGODB_ERROR_CODES.InterruptedAtShutdown,
680701
MONGODB_ERROR_CODES.InterruptedDueToReplStateChange,
681-
MONGODB_ERROR_CODES.NotMasterNoSlaveOk,
682-
MONGODB_ERROR_CODES.NotMasterOrSecondary
702+
MONGODB_ERROR_CODES.NotPrimaryNoSecondaryOk,
703+
MONGODB_ERROR_CODES.NotPrimaryOrSecondary
683704
]);
684705

685706
const RETRYABLE_WRITE_ERROR_CODES = new Set<number>([
686707
MONGODB_ERROR_CODES.InterruptedAtShutdown,
687708
MONGODB_ERROR_CODES.InterruptedDueToReplStateChange,
688-
MONGODB_ERROR_CODES.NotMaster,
689-
MONGODB_ERROR_CODES.NotMasterNoSlaveOk,
690-
MONGODB_ERROR_CODES.NotMasterOrSecondary,
709+
MONGODB_ERROR_CODES.NotWritablePrimary,
710+
MONGODB_ERROR_CODES.NotPrimaryNoSecondaryOk,
711+
MONGODB_ERROR_CODES.NotPrimaryOrSecondary,
691712
MONGODB_ERROR_CODES.PrimarySteppedDown,
692713
MONGODB_ERROR_CODES.ShutdownInProgress,
693714
MONGODB_ERROR_CODES.HostNotFound,
@@ -714,8 +735,8 @@ export function isRetryableError(error: MongoError): boolean {
714735
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
715736
(typeof error.code === 'number' && RETRYABLE_ERROR_CODES.has(error.code!)) ||
716737
error instanceof MongoNetworkError ||
717-
!!error.message.match(/not master/) ||
718-
!!error.message.match(/node is recovering/)
738+
!!error.message.match(new RegExp(LEGACY_NOT_WRITABLE_PRIMARY_ERROR_MESSAGE)) ||
739+
!!error.message.match(new RegExp(NODE_IS_RECOVERING_ERROR_MESSAGE))
719740
);
720741
}
721742

@@ -724,12 +745,12 @@ const SDAM_RECOVERING_CODES = new Set<number>([
724745
MONGODB_ERROR_CODES.PrimarySteppedDown,
725746
MONGODB_ERROR_CODES.InterruptedAtShutdown,
726747
MONGODB_ERROR_CODES.InterruptedDueToReplStateChange,
727-
MONGODB_ERROR_CODES.NotMasterOrSecondary
748+
MONGODB_ERROR_CODES.NotPrimaryOrSecondary
728749
]);
729750

730-
const SDAM_NOTMASTER_CODES = new Set<number>([
731-
MONGODB_ERROR_CODES.NotMaster,
732-
MONGODB_ERROR_CODES.NotMasterNoSlaveOk,
751+
const SDAM_NOTPRIMARY_CODES = new Set<number>([
752+
MONGODB_ERROR_CODES.NotWritablePrimary,
753+
MONGODB_ERROR_CODES.NotPrimaryNoSecondaryOk,
733754
MONGODB_ERROR_CODES.LegacyNotPrimary
734755
]);
735756

@@ -744,20 +765,23 @@ function isRecoveringError(err: MongoError) {
744765
return SDAM_RECOVERING_CODES.has(err.code);
745766
}
746767

747-
return /not master or secondary/.test(err.message) || /node is recovering/.test(err.message);
768+
return (
769+
new RegExp(LEGACY_NOT_PRIMARY_OR_SECONDARY_ERROR_MESSAGE).test(err.message) ||
770+
new RegExp(NODE_IS_RECOVERING_ERROR_MESSAGE).test(err.message)
771+
);
748772
}
749773

750-
function isNotMasterError(err: MongoError) {
774+
function isNotWritablePrimaryError(err: MongoError) {
751775
if (typeof err.code === 'number') {
752776
// If any error code exists, we ignore the error.message
753-
return SDAM_NOTMASTER_CODES.has(err.code);
777+
return SDAM_NOTPRIMARY_CODES.has(err.code);
754778
}
755779

756780
if (isRecoveringError(err)) {
757781
return false;
758782
}
759783

760-
return /not master/.test(err.message);
784+
return new RegExp(LEGACY_NOT_WRITABLE_PRIMARY_ERROR_MESSAGE).test(err.message);
761785
}
762786

763787
export function isNodeShuttingDownError(err: MongoError): boolean {
@@ -778,7 +802,7 @@ export function isSDAMUnrecoverableError(error: MongoError): boolean {
778802
return true;
779803
}
780804

781-
return isRecoveringError(error) || isNotMasterError(error);
805+
return isRecoveringError(error) || isNotWritablePrimaryError(error);
782806
}
783807

784808
export function isNetworkTimeoutError(err: MongoError): err is MongoNetworkError {

test/unit/error.test.js

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,17 @@ 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');
11+
const {
12+
LEGACY_NOT_WRITABLE_PRIMARY_ERROR_MESSAGE,
13+
LEGACY_NOT_PRIMARY_OR_SECONDARY_ERROR_MESSAGE,
14+
NODE_IS_RECOVERING_ERROR_MESSAGE
15+
} = require('../../src/error');
16+
const {
17+
isRetryableEndTransactionError,
18+
MongoParseError,
19+
isSDAMUnrecoverableError,
20+
MongoError
21+
} = require('../../src/error');
1222
const {
1323
PoolClosedError: MongoPoolClosedError,
1424
WaitQueueTimeoutError: MongoWaitQueueTimeoutError
@@ -65,6 +75,83 @@ describe('MongoErrors', () => {
6575
});
6676
});
6777

78+
describe('#isSDAMUnrecoverableError', function () {
79+
context('when the error is a MongoParseError', function () {
80+
it('returns true', function () {
81+
const error = new MongoParseError('');
82+
expect(isSDAMUnrecoverableError(error)).to.be.true;
83+
});
84+
});
85+
86+
context('when the error is null', function () {
87+
it('returns true', function () {
88+
expect(isSDAMUnrecoverableError(null)).to.be.true;
89+
});
90+
});
91+
92+
context('when the error has a "node is recovering" error code', function () {
93+
it('returns true', function () {
94+
const error = new MongoError('');
95+
// Code for NotPrimaryOrSecondary
96+
error.code = 13436;
97+
expect(isSDAMUnrecoverableError(error)).to.be.true;
98+
});
99+
});
100+
101+
context('when the error has a "not writable primary" error code', function () {
102+
it('returns true', function () {
103+
const error = new MongoError('');
104+
// Code for NotWritablePrimary
105+
error.code = 10107;
106+
expect(isSDAMUnrecoverableError(error)).to.be.true;
107+
});
108+
});
109+
110+
context(
111+
'when the code is not a "node is recovering" error and not a "not writable primary" error',
112+
function () {
113+
it('returns false', function () {
114+
// If the response includes an error code, it MUST be solely used to determine if error is a "node is recovering" or "not writable primary" error.
115+
const error = new MongoError(NODE_IS_RECOVERING_ERROR_MESSAGE);
116+
error.code = 555;
117+
expect(isSDAMUnrecoverableError(error)).to.be.false;
118+
});
119+
}
120+
);
121+
122+
context(
123+
'when the error message contains the legacy "not primary" message and no error code is used',
124+
function () {
125+
it('returns true', function () {
126+
const error = new MongoError(`this is ${LEGACY_NOT_WRITABLE_PRIMARY_ERROR_MESSAGE}.`);
127+
expect(isSDAMUnrecoverableError(error)).to.be.true;
128+
});
129+
}
130+
);
131+
132+
context(
133+
'when the error message contains "node is recovering" and no error code is used',
134+
function () {
135+
it('returns true', function () {
136+
const error = new MongoError(`the ${NODE_IS_RECOVERING_ERROR_MESSAGE} from an error`);
137+
expect(isSDAMUnrecoverableError(error)).to.be.true;
138+
});
139+
}
140+
);
141+
142+
context(
143+
'when the error message contains the legacy "not primary or secondary" message and no error code is used',
144+
function () {
145+
it('returns true', function () {
146+
const error = new MongoError(
147+
`this is ${LEGACY_NOT_PRIMARY_OR_SECONDARY_ERROR_MESSAGE}, so we have a problem `
148+
);
149+
expect(isSDAMUnrecoverableError(error)).to.be.true;
150+
});
151+
}
152+
);
153+
});
154+
68155
describe('when MongoNetworkError is constructed', () => {
69156
it('should only define beforeHandshake symbol if boolean option passed in', function () {
70157
const errorWithOptionTrue = new MongoNetworkError('', { beforeHandshake: true });

0 commit comments

Comments
 (0)