Skip to content

Commit 1951cf9

Browse files
changes!
1 parent 1eb704c commit 1951cf9

File tree

3 files changed

+34
-9
lines changed

3 files changed

+34
-9
lines changed

src/cmap/connect.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ import {
3535
/** @public */
3636
export type Stream = Socket | TLSSocket;
3737

38+
function applyBackpressureLabels(error: MongoError) {
39+
error.addErrorLabel(MongoErrorLabel.SystemOverloadedError);
40+
error.addErrorLabel(MongoErrorLabel.RetryableError);
41+
}
42+
3843
export async function connect(options: ConnectionOptions): Promise<Connection> {
3944
let connection: Connection | null = null;
4045
try {
@@ -103,6 +108,8 @@ export async function performInitialHandshake(
103108
const authContext = new AuthContext(conn, credentials, options);
104109
conn.authContext = authContext;
105110

111+
// If we encounter an error preparing the handshake document, do NOT apply backpressure labels. Errors
112+
// encountered building the handshake document are all client-side, and do not indicate an overloaded server.
106113
const handshakeDoc = await prepareHandshakeDocument(authContext);
107114

108115
// @ts-expect-error: TODO(NODE-5141): The options need to be filtered properly, Connection options differ from Command options
@@ -162,13 +169,19 @@ export async function performInitialHandshake(
162169

163170
try {
164171
await provider.auth(authContext);
165-
} catch (error) {
166-
if (error instanceof MongoError) {
167-
error.addErrorLabel(MongoErrorLabel.HandshakeError);
168-
if (needsRetryableWriteLabel(error, response.maxWireVersion, conn.description.type)) {
169-
error.addErrorLabel(MongoErrorLabel.RetryableWriteError);
170-
}
172+
} catch (cause) {
173+
// If we encounter an error authenticating a connection, do NOT apply backpressure labels.
174+
175+
const error =
176+
cause instanceof MongoError
177+
? cause
178+
: new MongoRuntimeError('unexpected error during authentication', cause);
179+
180+
error.addErrorLabel(MongoErrorLabel.HandshakeError);
181+
if (needsRetryableWriteLabel(error, response.maxWireVersion, conn.description.type)) {
182+
error.addErrorLabel(MongoErrorLabel.RetryableWriteError);
171183
}
184+
172185
throw error;
173186
}
174187
}
@@ -189,6 +202,9 @@ export async function performInitialHandshake(
189202
if (error instanceof MongoError) {
190203
error.addErrorLabel(MongoErrorLabel.HandshakeError);
191204
}
205+
// If we encounter an error executing the initial handshake, apply backpressure labels.
206+
applyBackpressureLabels(error);
207+
192208
throw error;
193209
}
194210
}
@@ -424,6 +440,8 @@ export async function makeSocket(options: MakeConnectionOptions): Promise<Stream
424440
socket = await connectedSocket;
425441
return socket;
426442
} catch (error) {
443+
// If we encounter a SystemOverloaded error while establishing a socket, apply the backpressure labels to it.
444+
applyBackpressureLabels(error);
427445
socket.destroy();
428446
throw error;
429447
} finally {

src/error.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,9 @@ export const MongoErrorLabel = Object.freeze({
9999
ResetPool: 'ResetPool',
100100
PoolRequestedRetry: 'PoolRequestedRetry',
101101
InterruptInUseConnections: 'InterruptInUseConnections',
102-
NoWritesPerformed: 'NoWritesPerformed'
102+
NoWritesPerformed: 'NoWritesPerformed',
103+
RetryableError: 'RetryableError',
104+
SystemOverloadedError: 'SystemOverloadedError'
103105
} as const);
104106

105107
/** @public */

src/sdam/server.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,8 @@ export class Server extends TypedEventEmitter<ServerEvents> {
400400
error instanceof MongoNetworkError && !(error instanceof MongoNetworkTimeoutError);
401401
const isNetworkTimeoutBeforeHandshakeError =
402402
error instanceof MongoNetworkError && error.beforeHandshake;
403-
const isAuthHandshakeError = error.hasErrorLabel(MongoErrorLabel.HandshakeError);
403+
const isAuthOrEstablishmentHandshakeError = error.hasErrorLabel(MongoErrorLabel.HandshakeError);
404+
const isSystemOverloadError = error.hasErrorLabel(MongoErrorLabel.SystemOverloadedError);
404405

405406
// TODO: considering parse errors as SDAM unrecoverable errors seem
406407
// questionable. What if the parse error only comes from an application connection,
@@ -430,8 +431,12 @@ export class Server extends TypedEventEmitter<ServerEvents> {
430431
} else if (
431432
isNetworkNonTimeoutError ||
432433
isNetworkTimeoutBeforeHandshakeError ||
433-
isAuthHandshakeError
434+
isAuthOrEstablishmentHandshakeError
434435
) {
436+
// Do NOT clear the pool if we encounter a system overloaded error.
437+
if (isSystemOverloadError) {
438+
return;
439+
}
435440
// from the SDAM spec: The driver MUST synchronize clearing the pool with updating the topology.
436441
// In load balanced mode: there is no monitoring, so there is no topology to update. We simply clear the pool.
437442
// For other topologies: the `ResetPool` label instructs the topology to clear the server's pool in `updateServer()`.

0 commit comments

Comments
 (0)