diff --git a/src/operations/execute_operation.ts b/src/operations/execute_operation.ts index 54fc3b99d6..a3e9f3d139 100644 --- a/src/operations/execute_operation.ts +++ b/src/operations/execute_operation.ts @@ -1,3 +1,5 @@ +import { setTimeout } from 'timers'; + import type { Document } from '../bson'; import { isRetryableReadError, @@ -224,23 +226,25 @@ function executeWithServerSelection( } // select a new server, and attempt to retry the operation - topology.selectServer(selector, serverSelectionOptions, (error?: Error, server?: Server) => { - if (!error && isWriteOperation && !supportsRetryableWrites(server)) { - return callback( - new MongoUnexpectedServerResponseError( - 'Selected server does not support retryable writes' - ) - ); - } + setTimeout(() => { + topology.selectServer(selector, serverSelectionOptions, (error?: Error, server?: Server) => { + if (!error && isWriteOperation && !supportsRetryableWrites(server)) { + return callback( + new MongoUnexpectedServerResponseError( + 'Selected server does not support retryable writes' + ) + ); + } - if (error || !server) { - return callback( - error ?? new MongoUnexpectedServerResponseError('Server selection failed without error') - ); - } + if (error || !server) { + return callback( + error ?? new MongoUnexpectedServerResponseError('Server selection failed without error') + ); + } - operation.execute(server, session, callback); - }); + operation.execute(server, session, callback); + }); + }, 1); } if ( diff --git a/src/sdam/server.ts b/src/sdam/server.ts index ac18d46756..dd8767bc70 100644 --- a/src/sdam/server.ts +++ b/src/sdam/server.ts @@ -5,6 +5,7 @@ import { ConnectionPoolEvents, ConnectionPoolOptions } from '../cmap/connection_pool'; +import { PoolClearedError } from '../cmap/errors'; import { APM_EVENTS, CLOSED, @@ -358,7 +359,11 @@ export class Server extends TypedEventEmitter { (err, conn, cb) => { if (err || !conn) { this.s.operationCount -= 1; - markServerUnknown(this, err); + if (!(err instanceof PoolClearedError)) { + markServerUnknown(this, err); + } else { + err.addErrorLabel(MongoErrorLabel.RetryableWriteError); + } return cb(err); } diff --git a/test/integration/server-discovery-and-monitoring/server_discovery_and_monitoring.spec.test.ts b/test/integration/server-discovery-and-monitoring/server_discovery_and_monitoring.spec.test.ts index bf80d89b15..be9e9c3cdb 100644 --- a/test/integration/server-discovery-and-monitoring/server_discovery_and_monitoring.spec.test.ts +++ b/test/integration/server-discovery-and-monitoring/server_discovery_and_monitoring.spec.test.ts @@ -19,8 +19,6 @@ const filter: TestFilter = ({ description }) => { return isAuthEnabled ? 'TODO(NODE-3135): handle auth errors, also see NODE-3891: fix tests broken when AUTH enabled' : false; - case 'PoolClearedError does not mark server unknown': - return 'TODO(NODE-3135): make CMAP SDAM-aware and ensure PoolClearError is retryable'; default: return false; } diff --git a/test/tools/unified-spec-runner/entities.ts b/test/tools/unified-spec-runner/entities.ts index 0ccced041e..95a93f2cbe 100644 --- a/test/tools/unified-spec-runner/entities.ts +++ b/test/tools/unified-spec-runner/entities.ts @@ -78,6 +78,7 @@ export class UnifiedThread { this.#killed = true; await this.#promise; if (this.#error) { + this.#error.message = `: ${this.#error.message}`; throw this.#error; } }