Skip to content

Commit c1231aa

Browse files
committed
2 parents 36ab7b1 + 30b23ba commit c1231aa

File tree

8 files changed

+62
-76
lines changed

8 files changed

+62
-76
lines changed

.evergreen/config.yml

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1877,19 +1877,6 @@ tasks:
18771877
- func: install dependencies
18781878
- func: bootstrap mongo-orchestration
18791879
- func: check resource management feature integration
1880-
- name: check-types-typescript-next
1881-
tags:
1882-
- check-types-typescript-next
1883-
- typescript-compilation
1884-
commands:
1885-
- command: expansions.update
1886-
type: setup
1887-
params:
1888-
updates:
1889-
- {key: NODE_LTS_VERSION, value: 20.19.0}
1890-
- {key: TS_VERSION, value: next}
1891-
- func: install dependencies
1892-
- func: check types
18931880
- name: check-types-typescript-current
18941881
tags:
18951882
- check-types-typescript-current

.evergreen/generate_evergreen_tasks.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,8 @@ function* makeTypescriptTasks() {
532532
};
533533
}
534534

535-
yield makeCheckTypesTask('next');
535+
// TODO(NODE-7233): unskip ts@next tests once we adopt Typescript 6.0.
536+
// yield makeCheckTypesTask('next');
536537
yield makeCheckTypesTask('current');
537538
yield makeCheckTypesTask('5.6');
538539

src/cmap/auth/mongo_credentials.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ export const DEFAULT_ALLOWED_HOSTS = [
4545
'*.mongodbgov.net',
4646
'localhost',
4747
'127.0.0.1',
48-
'::1'
48+
'::1',
49+
'*.mongo.com'
4950
];
5051

5152
/** Error for when the token audience is missing in the environment. */

src/db.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,6 @@ export class Db {
394394
toCollection,
395395
resolveOptions(undefined, {
396396
...options,
397-
new_collection: true,
398397
readPreference: ReadPreference.primary
399398
})
400399
) as TODO_NODE_3286

src/error.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1528,13 +1528,7 @@ export function isNodeShuttingDownError(err: MongoError): boolean {
15281528
*
15291529
* @see https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-discovery-and-monitoring.md#not-writable-primary-and-node-is-recovering
15301530
*/
1531-
export function isSDAMUnrecoverableError(error: MongoError): boolean {
1532-
// NOTE: null check is here for a strictly pre-CMAP world, a timeout or
1533-
// close event are considered unrecoverable
1534-
if (error instanceof MongoParseError || error == null) {
1535-
return true;
1536-
}
1537-
1531+
export function isStateChangeError(error: MongoError): boolean {
15381532
return isRecoveringError(error) || isNotWritablePrimaryError(error);
15391533
}
15401534

src/operations/rename.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,12 @@ import { Aspect, defineAspects } from './operation';
1111
export interface RenameOptions extends Omit<CommandOperationOptions, 'rawData'> {
1212
/** Drop the target name collection if it previously exists. */
1313
dropTarget?: boolean;
14-
/** Unclear */
14+
/**
15+
* @deprecated
16+
*
17+
* This option has been dead code since at least Node driver version 4.x. It will
18+
* be removed in a future major release.
19+
*/
1520
new_collection?: boolean;
1621
}
1722

src/sdam/server.ts

Lines changed: 43 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,13 @@ import {
2222
import {
2323
type AnyError,
2424
isNodeShuttingDownError,
25-
isSDAMUnrecoverableError,
25+
isStateChangeError,
2626
MONGODB_ERROR_CODES,
2727
MongoError,
2828
MongoErrorLabel,
2929
MongoNetworkError,
3030
MongoNetworkTimeoutError,
31+
MongoParseError,
3132
MongoRuntimeError,
3233
MongoServerClosedError,
3334
type MongoServerError,
@@ -391,9 +392,7 @@ export class Server extends TypedEventEmitter<ServerEvents> {
391392
return;
392393
}
393394

394-
const isStaleError =
395-
error.connectionGeneration && error.connectionGeneration < this.pool.generation;
396-
if (isStaleError) {
395+
if (isStaleError(this, error)) {
397396
return;
398397
}
399398

@@ -402,32 +401,40 @@ export class Server extends TypedEventEmitter<ServerEvents> {
402401
const isNetworkTimeoutBeforeHandshakeError =
403402
error instanceof MongoNetworkError && error.beforeHandshake;
404403
const isAuthHandshakeError = error.hasErrorLabel(MongoErrorLabel.HandshakeError);
405-
if (isNetworkNonTimeoutError || isNetworkTimeoutBeforeHandshakeError || isAuthHandshakeError) {
406-
// In load balanced mode we never mark the server as unknown and always
407-
// clear for the specific service id.
404+
405+
// Perhaps questionable and divergent from the spec, but considering MongoParseErrors like state change errors was legacy behavior.
406+
if (isStateChangeError(error) || error instanceof MongoParseError) {
407+
const shouldClearPool = isNodeShuttingDownError(error);
408+
409+
// from the SDAM spec: The driver MUST synchronize clearing the pool with updating the topology.
410+
// In load balanced mode: there is no monitoring, so there is no topology to update. We simply clear the pool.
411+
// For other topologies: the `ResetPool` label instructs the topology to clear the server's pool in `updateServer()`.
412+
if (!this.loadBalanced) {
413+
if (shouldClearPool) {
414+
error.addErrorLabel(MongoErrorLabel.ResetPool);
415+
}
416+
markServerUnknown(this, error);
417+
process.nextTick(() => this.requestCheck());
418+
return;
419+
}
420+
421+
if (connection && shouldClearPool) {
422+
this.pool.clear({ serviceId: connection.serviceId });
423+
}
424+
} else if (
425+
isNetworkNonTimeoutError ||
426+
isNetworkTimeoutBeforeHandshakeError ||
427+
isAuthHandshakeError
428+
) {
429+
// from the SDAM spec: The driver MUST synchronize clearing the pool with updating the topology.
430+
// In load balanced mode: there is no monitoring, so there is no topology to update. We simply clear the pool.
431+
// For other topologies: the `ResetPool` label instructs the topology to clear the server's pool in `updateServer()`.
408432
if (!this.loadBalanced) {
409433
error.addErrorLabel(MongoErrorLabel.ResetPool);
410434
markServerUnknown(this, error);
411435
} else if (connection) {
412436
this.pool.clear({ serviceId: connection.serviceId });
413437
}
414-
} else {
415-
if (isSDAMUnrecoverableError(error)) {
416-
if (shouldHandleStateChangeError(this, error)) {
417-
const shouldClearPool = isNodeShuttingDownError(error);
418-
if (this.loadBalanced && connection && shouldClearPool) {
419-
this.pool.clear({ serviceId: connection.serviceId });
420-
}
421-
422-
if (!this.loadBalanced) {
423-
if (shouldClearPool) {
424-
error.addErrorLabel(MongoErrorLabel.ResetPool);
425-
}
426-
markServerUnknown(this, error);
427-
process.nextTick(() => this.requestCheck());
428-
}
429-
}
430-
}
431438
}
432439
}
433440

@@ -560,12 +567,6 @@ function connectionIsStale(pool: ConnectionPool, connection: Connection) {
560567
return connection.generation !== pool.generation;
561568
}
562569

563-
function shouldHandleStateChangeError(server: Server, err: MongoError) {
564-
const etv = err.topologyVersion;
565-
const stv = server.description.topologyVersion;
566-
return compareTopologyVersion(stv, etv) < 0;
567-
}
568-
569570
function inActiveTransaction(session: ClientSession | undefined, cmd: Document) {
570571
return session && session.inTransaction() && !isTransactionCommand(cmd);
571572
}
@@ -575,3 +576,15 @@ function inActiveTransaction(session: ClientSession | undefined, cmd: Document)
575576
function isRetryableWritesEnabled(topology: Topology) {
576577
return topology.s.options.retryWrites !== false;
577578
}
579+
580+
function isStaleError(server: Server, error: MongoError): boolean {
581+
const currentGeneration = server.pool.generation;
582+
const generation = error.connectionGeneration;
583+
584+
if (generation && generation < currentGeneration) {
585+
return true;
586+
}
587+
588+
const currentTopologyVersion = server.description.topologyVersion;
589+
return compareTopologyVersion(currentTopologyVersion, error.topologyVersion) >= 0;
590+
}

test/unit/error.test.ts

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import * as importsFromErrorSrc from '../../src/error';
1010
import {
1111
isResumableError,
1212
isRetryableReadError,
13-
isSDAMUnrecoverableError,
13+
isStateChangeError,
1414
LEGACY_NOT_PRIMARY_OR_SECONDARY_ERROR_MESSAGE,
1515
LEGACY_NOT_WRITABLE_PRIMARY_ERROR_MESSAGE,
1616
MONGODB_ERROR_CODES,
@@ -26,7 +26,6 @@ import {
2626
MongoNetworkError,
2727
MongoNetworkTimeoutError,
2828
MongoOperationTimeoutError,
29-
MongoParseError,
3029
MongoRuntimeError,
3130
MongoServerError,
3231
MongoSystemError,
@@ -211,26 +210,13 @@ describe('MongoErrors', () => {
211210
});
212211
});
213212

214-
describe('#isSDAMUnrecoverableError', function () {
215-
context('when the error is a MongoParseError', function () {
216-
it('returns true', function () {
217-
const error = new MongoParseError('');
218-
expect(isSDAMUnrecoverableError(error)).to.be.true;
219-
});
220-
});
221-
222-
context('when the error is null', function () {
223-
it('returns true', function () {
224-
expect(isSDAMUnrecoverableError(null)).to.be.true;
225-
});
226-
});
227-
213+
describe('#isStateChangeError', function () {
228214
context('when the error has a "node is recovering" error code', function () {
229215
it('returns true', function () {
230216
const error = new MongoError('');
231217
// Code for NotPrimaryOrSecondary
232218
error.code = 13436;
233-
expect(isSDAMUnrecoverableError(error)).to.be.true;
219+
expect(isStateChangeError(error)).to.be.true;
234220
});
235221
});
236222

@@ -239,7 +225,7 @@ describe('MongoErrors', () => {
239225
const error = new MongoError('');
240226
// Code for NotWritablePrimary
241227
error.code = 10107;
242-
expect(isSDAMUnrecoverableError(error)).to.be.true;
228+
expect(isStateChangeError(error)).to.be.true;
243229
});
244230
});
245231

@@ -250,7 +236,7 @@ describe('MongoErrors', () => {
250236
// 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.
251237
const error = new MongoError(NODE_IS_RECOVERING_ERROR_MESSAGE.source);
252238
error.code = 555;
253-
expect(isSDAMUnrecoverableError(error)).to.be.false;
239+
expect(isStateChangeError(error)).to.be.false;
254240
});
255241
}
256242
);
@@ -262,7 +248,7 @@ describe('MongoErrors', () => {
262248
const error = new MongoError(
263249
`this is ${LEGACY_NOT_WRITABLE_PRIMARY_ERROR_MESSAGE.source}.`
264250
);
265-
expect(isSDAMUnrecoverableError(error)).to.be.true;
251+
expect(isStateChangeError(error)).to.be.true;
266252
});
267253
}
268254
);
@@ -272,7 +258,7 @@ describe('MongoErrors', () => {
272258
function () {
273259
it('returns true', function () {
274260
const error = new MongoError(`the ${NODE_IS_RECOVERING_ERROR_MESSAGE} from an error`);
275-
expect(isSDAMUnrecoverableError(error)).to.be.true;
261+
expect(isStateChangeError(error)).to.be.true;
276262
});
277263
}
278264
);
@@ -284,7 +270,7 @@ describe('MongoErrors', () => {
284270
const error = new MongoError(
285271
`this is ${LEGACY_NOT_PRIMARY_OR_SECONDARY_ERROR_MESSAGE}, so we have a problem `
286272
);
287-
expect(isSDAMUnrecoverableError(error)).to.be.true;
273+
expect(isStateChangeError(error)).to.be.true;
288274
});
289275
}
290276
);

0 commit comments

Comments
 (0)