From 385043186a80a5e330606f4c2492ade03512aa94 Mon Sep 17 00:00:00 2001 From: bailey Date: Fri, 21 Nov 2025 10:59:35 -0700 Subject: [PATCH 01/12] add token bucket --- src/token_bucket.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/token_bucket.ts diff --git a/src/token_bucket.ts b/src/token_bucket.ts new file mode 100644 index 0000000000..fddacdb657 --- /dev/null +++ b/src/token_bucket.ts @@ -0,0 +1,20 @@ +export class TokenBucket { + private budget: number; + constructor(allowance: number) { + this.budget = allowance; + } + deposit(tokens: number) { + this.budget += tokens; + } + + consume(tokens: number): boolean { + if (tokens > this.budget) return false; + + this.budget -= tokens; + return true; + } +} + +export const TOKEN_REFRESH_RATE = 0.1; +export const INITIAL_SIZE = 1000; +export const RETRY_COST = 1; From aa67999936b60c06689690ca4e951be95ae01ab4 Mon Sep 17 00:00:00 2001 From: bailey Date: Tue, 25 Nov 2025 12:10:24 -0700 Subject: [PATCH 02/12] use token bucket and apply exponential backoff in retry loop --- src/operations/execute_operation.ts | 160 ++++++++++++++++++++-------- src/sdam/topology.ts | 8 +- 2 files changed, 116 insertions(+), 52 deletions(-) diff --git a/src/operations/execute_operation.ts b/src/operations/execute_operation.ts index b6ddbba2b6..6afd5a577c 100644 --- a/src/operations/execute_operation.ts +++ b/src/operations/execute_operation.ts @@ -1,3 +1,5 @@ +import { setTimeout } from 'node:timers/promises'; + import { MIN_SUPPORTED_SNAPSHOT_READS_WIRE_VERSION } from '../cmap/wire_protocol/constants'; import { isRetryableReadError, @@ -10,6 +12,7 @@ import { MongoInvalidArgumentError, MongoNetworkError, MongoNotConnectedError, + MongoOperationTimeoutError, MongoRuntimeError, MongoServerError, MongoTransactionError, @@ -26,6 +29,7 @@ import { import type { Topology } from '../sdam/topology'; import type { ClientSession } from '../sessions'; import { TimeoutContext } from '../timeout'; +import { RETRY_COST, TOKEN_REFRESH_RATE } from '../token_bucket'; import { abortable, maxWireVersion, supportsRetryableWrites } from '../utils'; import { AggregateOperation } from './aggregate'; import { AbstractOperation, Aspect } from './operation'; @@ -233,71 +237,138 @@ async function tryOperation maxSystemOverloadRetryAttempts) { + throw previousOperationError; + } + + const delayMS = + Math.random() * + Math.min( + 10_000, // MAX_BACKOFF, + 100 * 2 ** systemOverloadRetryAttempt + ); + + // if the delay would exhaust the CSOT timeout, short-circuit. + if (timeoutContext.csotEnabled() && delayMS > timeoutContext.remainingTimeMS) { + // TODO: is this the right error to throw? + throw new MongoOperationTimeoutError( + `MongoDB SystemOverload exponential backoff would exceed timeoutMS deadline: remaining CSOT deadline=${timeoutContext.remainingTimeMS}, backoff delayMS=${delayMS}`, + { + cause: previousOperationError + } + ); + } + + await setTimeout(delayMS); + + if (!topology.tokenBucket.consume(RETRY_COST)) { + throw previousOperationError; + } + + server = await topology.selectServer(selector, { + session, + operationName: operation.commandName, + deprioritizedServers, + signal: operation.options.signal + }); + } else { + // we have no more retry attempts, throw. + if (nonOverloadRetryAttempt >= maxNonOverloadRetryAttempts) { + throw previousOperationError; + } + + if (hasWriteAspect && previousOperationError.code === MMAPv1_RETRY_WRITES_ERROR_CODE) { + throw new MongoServerError({ + message: MMAPv1_RETRY_WRITES_ERROR_MESSAGE, + errmsg: MMAPv1_RETRY_WRITES_ERROR_MESSAGE, + originalError: previousOperationError + }); + } + + if ( + (operation.hasAspect(Aspect.COMMAND_BATCHING) && !operation.canRetryWrite) || + (hasWriteAspect && !isRetryableWriteError(previousOperationError)) || + (hasReadAspect && !isRetryableReadError(previousOperationError)) + ) { + throw previousOperationError; + } + + if ( + previousOperationError instanceof MongoNetworkError && + operation.hasAspect(Aspect.CURSOR_CREATING) && + session != null && + session.isPinned && + !session.inTransaction() + ) { + session.unpin({ force: true, forceClear: true }); + } + + server = await topology.selectServer(selector, { + session, + operationName: operation.commandName, + deprioritizedServers, + signal: operation.options.signal }); - } - - if (operation.hasAspect(Aspect.COMMAND_BATCHING) && !operation.canRetryWrite) { - throw previousOperationError; - } - - if (hasWriteAspect && !isRetryableWriteError(previousOperationError)) - throw previousOperationError; - - if (hasReadAspect && !isRetryableReadError(previousOperationError)) { - throw previousOperationError; - } - - if ( - previousOperationError instanceof MongoNetworkError && - operation.hasAspect(Aspect.CURSOR_CREATING) && - session != null && - session.isPinned && - !session.inTransaction() - ) { - session.unpin({ force: true, forceClear: true }); - } - - server = await topology.selectServer(selector, { - session, - operationName: operation.commandName, - deprioritizedServers, - signal: operation.options.signal - }); - if (hasWriteAspect && !supportsRetryableWrites(server)) { - throw new MongoUnexpectedServerResponseError( - 'Selected server does not support retryable writes' - ); + if (hasWriteAspect && !supportsRetryableWrites(server)) { + throw new MongoUnexpectedServerResponseError( + 'Selected server does not support retryable writes' + ); + } } } operation.server = server; try { - // If tries > 0 and we are command batching we need to reset the batch. - if (tries > 0 && operation.hasAspect(Aspect.COMMAND_BATCHING)) { + // If attempt > 0 and we are command batching we need to reset the batch. + if (nonOverloadRetryAttempt > 0 && operation.hasAspect(Aspect.COMMAND_BATCHING)) { operation.resetBatch(); } try { const result = await server.command(operation, timeoutContext); + const isRetry = nonOverloadRetryAttempt > 0 || systemOverloadRetryAttempt > 0; + topology.tokenBucket.deposit( + isRetry + ? // on successful retry, deposit the retry cost + the refresh rate. + TOKEN_REFRESH_RATE + RETRY_COST + : // otherwise, just deposit the refresh rate. + TOKEN_REFRESH_RATE + ); return operation.handleOk(result); } catch (error) { return operation.handleError(error); } } catch (operationError) { if (!(operationError instanceof MongoError)) throw operationError; + + if (!operationError.hasErrorLabel(MongoErrorLabel.SystemOverloadError)) { + // if an operation fails with an error that does not contain the SystemOverloadError, deposit 1 token. + topology.tokenBucket.deposit(RETRY_COST); + } + if ( previousOperationError != null && operationError.hasErrorLabel(MongoErrorLabel.NoWritesPerformed) @@ -311,9 +382,4 @@ async function tryOperation { - /** @internal */ s: TopologyPrivate; - /** @internal */ waitQueue: List; - /** @internal */ hello?: Document; - /** @internal */ _type?: string; + tokenBucket = new TokenBucket(1000); + client!: MongoClient; - /** @internal */ private connectionLock?: Promise; /** @event */ From a62a5b235c29615f1927f9ccaf2bcbe45b2fc586 Mon Sep 17 00:00:00 2001 From: bailey Date: Tue, 25 Nov 2025 14:20:16 -0700 Subject: [PATCH 03/12] retryability cleanup changes --- src/operations/execute_operation.ts | 32 +++++++++++++++++++++-------- src/utils.ts | 10 +++++++++ 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/operations/execute_operation.ts b/src/operations/execute_operation.ts index 6afd5a577c..1137a94f2f 100644 --- a/src/operations/execute_operation.ts +++ b/src/operations/execute_operation.ts @@ -30,7 +30,12 @@ import type { Topology } from '../sdam/topology'; import type { ClientSession } from '../sessions'; import { TimeoutContext } from '../timeout'; import { RETRY_COST, TOKEN_REFRESH_RATE } from '../token_bucket'; -import { abortable, maxWireVersion, supportsRetryableWrites } from '../utils'; +import { + abortable, + exponentialBackoffDelayProvider, + maxWireVersion, + supportsRetryableWrites +} from '../utils'; import { AggregateOperation } from './aggregate'; import { AbstractOperation, Aspect } from './operation'; @@ -246,14 +251,28 @@ async function tryOperation timeoutContext.remainingTimeMS) { diff --git a/src/utils.ts b/src/utils.ts index c0f0864dbf..574c950fbe 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1431,3 +1431,13 @@ export async function abortable( abortListener?.[kDispose](); } } + +export function* exponentialBackoffDelayProvider( + maxBackoff: number, + baseBackoff: number, + backoffIncreaseRate: number +): Generator { + for (let i = 0; ; i++) { + yield Math.random() * Math.min(maxBackoff, baseBackoff * backoffIncreaseRate ** i); + } +} From 76d18ffd829c1d1d6062f5a11363dab6ac818ba0 Mon Sep 17 00:00:00 2001 From: bailey Date: Tue, 25 Nov 2025 16:32:46 -0700 Subject: [PATCH 04/12] initial POC --- src/operations/execute_operation.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/operations/execute_operation.ts b/src/operations/execute_operation.ts index 1137a94f2f..d87f9e0e50 100644 --- a/src/operations/execute_operation.ts +++ b/src/operations/execute_operation.ts @@ -59,7 +59,7 @@ type ResultTypeFromOperation = ReturnType< * The expectation is that this function: * - Connects the MongoClient if it has not already been connected, see {@link autoConnect} * - Creates a session if none is provided and cleans up the session it creates - * - Tries an operation and retries under certain conditions, see {@link tryOperation} + * - Tries an operation and retries under certain conditions, see {@link executeOperationWithRetries} * * @typeParam T - The operation's type * @typeParam TResult - The type of the operation's result, calculated from T @@ -129,7 +129,7 @@ export async function executeOperation< }); try { - return await tryOperation(operation, { + return await executeOperationWithRetries(operation, { topology, timeoutContext, session, @@ -193,7 +193,10 @@ type RetryOptions = { * * @param operation - The operation to execute * */ -async function tryOperation>( +async function executeOperationWithRetries< + T extends AbstractOperation, + TResult = ResultTypeFromOperation +>( operation: T, { topology, timeoutContext, session, readPreference }: RetryOptions ): Promise { @@ -247,7 +250,7 @@ async function tryOperation maxSystemOverloadRetryAttempts) { + if (systemOverloadRetryAttempt >= maxSystemOverloadRetryAttempts) { throw previousOperationError; } @@ -307,6 +310,7 @@ async function tryOperation= maxNonOverloadRetryAttempts) { throw previousOperationError; @@ -378,7 +382,7 @@ async function tryOperation Date: Mon, 1 Dec 2025 13:52:15 -0700 Subject: [PATCH 05/12] Add tests for retry loop and backoff. --- src/cmap/connect.ts | 2 + src/index.ts | 1 + src/operations/execute_operation.ts | 22 +- src/token_bucket.ts | 3 + sync.sh | 3 + .../client-backpressure.prose.test.ts | 60 + .../client-backpressure.spec.test.ts | 16 + .../mongodb-handshake.prose.test.ts | 44 +- test/spec/client-backpressure/README.md | 61 + .../backpressure-retry-loop.json | 2973 ++++++++++++++ .../backpressure-retry-loop.yml | 1596 ++++++++ .../backpressure-retry-loop.yml.template | 114 + .../backpressure-retry-max-attempts.json | 3445 +++++++++++++++++ .../backpressure-retry-max-attempts.yml | 1841 +++++++++ ...ckpressure-retry-max-attempts.yml.template | 108 + 15 files changed, 10279 insertions(+), 10 deletions(-) create mode 100644 sync.sh create mode 100644 test/integration/client-backpressure/client-backpressure.prose.test.ts create mode 100644 test/integration/client-backpressure/client-backpressure.spec.test.ts create mode 100644 test/spec/client-backpressure/README.md create mode 100644 test/spec/client-backpressure/backpressure-retry-loop.json create mode 100644 test/spec/client-backpressure/backpressure-retry-loop.yml create mode 100644 test/spec/client-backpressure/backpressure-retry-loop.yml.template create mode 100644 test/spec/client-backpressure/backpressure-retry-max-attempts.json create mode 100644 test/spec/client-backpressure/backpressure-retry-max-attempts.yml create mode 100644 test/spec/client-backpressure/backpressure-retry-max-attempts.yml.template diff --git a/src/cmap/connect.ts b/src/cmap/connect.ts index 544ec471a9..711335f3d1 100644 --- a/src/cmap/connect.ts +++ b/src/cmap/connect.ts @@ -224,6 +224,7 @@ export interface HandshakeDocument extends Document { compression: string[]; saslSupportedMechs?: string; loadBalanced?: boolean; + backpressure: true; } /** @@ -241,6 +242,7 @@ export async function prepareHandshakeDocument( const handshakeDoc: HandshakeDocument = { [serverApi?.version || options.loadBalanced === true ? 'hello' : LEGACY_HELLO_COMMAND]: 1, + backpressure: true, helloOk: true, client: clientMetadata, compression: compressors diff --git a/src/index.ts b/src/index.ts index 8f5c4cfa60..ca66d31e20 100644 --- a/src/index.ts +++ b/src/index.ts @@ -87,6 +87,7 @@ export { MongoWriteConcernError, WriteConcernErrorResult } from './error'; +export { TokenBucket } from './token_bucket'; export { AbstractCursor, // Actual driver classes exported diff --git a/src/operations/execute_operation.ts b/src/operations/execute_operation.ts index d87f9e0e50..31f7133769 100644 --- a/src/operations/execute_operation.ts +++ b/src/operations/execute_operation.ts @@ -38,6 +38,7 @@ import { } from '../utils'; import { AggregateOperation } from './aggregate'; import { AbstractOperation, Aspect } from './operation'; +import { RunCommandOperation } from './run_command'; const MMAPv1_RETRY_WRITES_ERROR_CODE = MONGODB_ERROR_CODES.IllegalOperation; const MMAPv1_RETRY_WRITES_ERROR_MESSAGE = @@ -265,22 +266,22 @@ async function executeOperationWithRetries< if (previousOperationError.hasErrorLabel(MongoErrorLabel.SystemOverloadedError)) { systemOverloadRetryAttempt += 1; + // if retryable writes or reads are not configured, throw. + const isOperationConfiguredForRetry = + (hasReadAspect && topology.s.options.retryReads) || + (hasWriteAspect && topology.s.options.retryWrites); + const isRunCommand = operation instanceof RunCommandOperation; + if ( // if the SystemOverloadError is not retryable, throw. !previousOperationError.hasErrorLabel(MongoErrorLabel.RetryableError) || - !( - // if retryable writes or reads are not configured, throw. - ( - (hasReadAspect && topology.s.options.retryReads) || - (hasWriteAspect && topology.s.options.retryWrites) - ) - ) + !(isOperationConfiguredForRetry || isRunCommand) ) { throw previousOperationError; } // if we have exhausted overload retry attempts, throw. - if (systemOverloadRetryAttempt >= maxSystemOverloadRetryAttempts) { + if (systemOverloadRetryAttempt > maxSystemOverloadRetryAttempts) { throw previousOperationError; } @@ -361,7 +362,10 @@ async function executeOperationWithRetries< try { // If attempt > 0 and we are command batching we need to reset the batch. - if (nonOverloadRetryAttempt > 0 && operation.hasAspect(Aspect.COMMAND_BATCHING)) { + if ( + (nonOverloadRetryAttempt > 0 || systemOverloadRetryAttempt > 0) && + operation.hasAspect(Aspect.COMMAND_BATCHING) + ) { operation.resetBatch(); } diff --git a/src/token_bucket.ts b/src/token_bucket.ts index fddacdb657..9d542bf719 100644 --- a/src/token_bucket.ts +++ b/src/token_bucket.ts @@ -1,3 +1,6 @@ +/** + * @internal + */ export class TokenBucket { private budget: number; constructor(allowance: number) { diff --git a/sync.sh b/sync.sh new file mode 100644 index 0000000000..aab954ba4e --- /dev/null +++ b/sync.sh @@ -0,0 +1,3 @@ + + +cp ~/dev/specifications/source/client-backpressure/tests/* ~/dev/node-mongodb-native/test/spec/client-backpressure \ No newline at end of file diff --git a/test/integration/client-backpressure/client-backpressure.prose.test.ts b/test/integration/client-backpressure/client-backpressure.prose.test.ts new file mode 100644 index 0000000000..56d274fffe --- /dev/null +++ b/test/integration/client-backpressure/client-backpressure.prose.test.ts @@ -0,0 +1,60 @@ +import { expect } from 'chai'; +import * as sinon from 'sinon'; + +import { type Collection, type MongoClient, MongoServerError } from '../../../src'; +import { clearFailPoint, configureFailPoint, measureDuration } from '../../tools/utils'; + +describe('Client Backpressure (Prose)', function () { + let client: MongoClient; + let collection: Collection; + + beforeEach(async function () { + client = this.configuration.newClient(); + await client.connect(); + + collection = client.db('foo').collection('bar'); + }); + + afterEach(async function () { + await client.close(); + await clearFailPoint(this.configuration); + }); + + it( + 'Test 1: Operation Retry Uses Exponential Backoff', + { + requires: { + mongodb: '4.4' + } + }, + async function () { + await configureFailPoint(this.configuration, { + configureFailPoint: 'failCommand', + mode: 'alwaysOn', + data: { + failCommands: ['insert'], + errorCode: 2, + errorLabels: ['SystemOverloadedError', 'RetryableError'] + } + }); + + const stub = sinon.stub(Math, 'random'); + + stub.returns(0); + + const { duration: durationNoBackoff } = await measureDuration(async () => { + const error = await collection.insertOne({ a: 1 }).catch(e => e); + expect(error).to.be.instanceof(MongoServerError); + }); + + stub.returns(1); + + const { duration: durationBackoff } = await measureDuration(async () => { + const error = await collection.insertOne({ a: 1 }).catch(e => e); + expect(error).to.be.instanceof(MongoServerError); + }); + + expect(durationBackoff - durationNoBackoff).to.be.within(3100 - 1000, 3100 + 1000); + } + ); +}); diff --git a/test/integration/client-backpressure/client-backpressure.spec.test.ts b/test/integration/client-backpressure/client-backpressure.spec.test.ts new file mode 100644 index 0000000000..9485c46a96 --- /dev/null +++ b/test/integration/client-backpressure/client-backpressure.spec.test.ts @@ -0,0 +1,16 @@ +import { loadSpecTests } from '../../spec'; +import { runUnifiedSuite } from '../../tools/unified-spec-runner/runner'; +import { type Test } from '../../tools/unified-spec-runner/schema'; + +const skippedTests = { + 'collection.dropIndexes retries at most maxAttempts=5 times': + 'TODO(NODE-6517): dropIndexes squashes all errors other than ns not found' +}; + +function shouldSkip({ description }: Test) { + return skippedTests[description] ?? false; +} + +describe('Client Backpressure (spec)', function () { + runUnifiedSuite(loadSpecTests('client-backpressure'), shouldSkip); +}); diff --git a/test/integration/mongodb-handshake/mongodb-handshake.prose.test.ts b/test/integration/mongodb-handshake/mongodb-handshake.prose.test.ts index a8ac32b99c..dd04c8d182 100644 --- a/test/integration/mongodb-handshake/mongodb-handshake.prose.test.ts +++ b/test/integration/mongodb-handshake/mongodb-handshake.prose.test.ts @@ -1,7 +1,14 @@ import { expect } from 'chai'; import * as sinon from 'sinon'; -import { type ClientMetadata, type DriverInfo, Int32, MongoClient } from '../../../src'; +import { + type ClientMetadata, + type Document, + type DriverInfo, + type HandshakeDocument, + Int32, + MongoClient +} from '../../../src'; import { Connection } from '../../../src/cmap/connection'; import { getFAASEnv, isDriverInfoEqual } from '../../../src/cmap/handshake/client_metadata'; import { LEGACY_HELLO_COMMAND } from '../../../src/constants'; @@ -939,3 +946,38 @@ describe('Client Metadata Update Prose Tests', function () { } }); }); + +// TODO: add prose test descriptions here to align the test with the spec. +describe('Backpressure Metadata', function () { + let client: MongoClient; + let spy: sinon.SinonSpy>; + + beforeEach(async function () { + client = this.configuration.newClient(); + spy = sinon.spy(Connection.prototype, 'command'); + await client.connect(); + + // run an operation to force a connection establishment, + // if we're testing noauth load balanced mode. + await client.db('foo').collection('bar').insertOne({ name: 'bumpy' }); + }); + + afterEach(async function () { + sinon.restore(); + await client?.close(); + }); + + it('includes backpressure in the handshake document', function () { + const isHello = (cmd: Document): cmd is HandshakeDocument => + `hello` in cmd || LEGACY_HELLO_COMMAND in cmd; + + const hellos = spy.args.map(([_ns, command, _options]) => command).filter(isHello); + + expect(hellos.length).to.be.greaterThan(0); + + expect( + hellos.every(hello => hello.backpressure === true), + `some handshake documents did not specify backpressure: true` + ); + }); +}); diff --git a/test/spec/client-backpressure/README.md b/test/spec/client-backpressure/README.md new file mode 100644 index 0000000000..41ad017c6c --- /dev/null +++ b/test/spec/client-backpressure/README.md @@ -0,0 +1,61 @@ +# Client Backpressure Tests + +______________________________________________________________________ + +## Introduction + +The YAML and JSON files in this directory are platform-independent tests meant to exercise a driver's implementation of +retryable reads. These tests utilize the [Unified Test Format](../../unified-test-format/unified-test-format.md). + +Several prose tests, which are not easily expressed in YAML, are also presented in this file. Those tests will need to +be manually implemented by each driver. + +### Prose Tests + +#### Test 1: Operation Retry Uses Exponential Backoff + +Drivers should test that retries do not occur immediately when a SystemOverloadedError is encountered. + +1. let `client` be a `MongoClient` +2. let `collection` be a collection +3. Now, run transactions without backoff: + 1. Configure the random number generator used for jitter to always return `0` -- this effectively disables backoff. + + 2. Configure the following failPoint: + + ```javascript + { + configureFailPoint: 'failCommand', + mode: 'alwaysOn', + data: { + failCommands: ['insert'], + errorCode: 2, + errorLabels: ['SystemOverloadedError', 'RetryableError'] + } + } + ``` + + 3. Execute the following command. Expect that the command errors. Measure the duration of the command execution. + + ```javascript + const start = performance.now(); + expect( + await coll.insertOne({ a: 1 }).catch(e => e) + ).to.be.an.instanceof(MongoServerError); + const end = performance.now(); + ``` + + 4. Configure the random number generator used for jitter to always return `1`. + + 5. Execute step 3 again. + + 6. Compare the two time between the two runs. + ```python + assertTrue(with_backoff_time - no_backoff_time >= 2.1) + ``` + The sum of 5 backoffs is 3.1 seconds. There is a 1-second window to account for potential variance between the two + runs. + +## Changelog + +- 2025-XX-XX: Initial version. diff --git a/test/spec/client-backpressure/backpressure-retry-loop.json b/test/spec/client-backpressure/backpressure-retry-loop.json new file mode 100644 index 0000000000..79cfc4bac7 --- /dev/null +++ b/test/spec/client-backpressure/backpressure-retry-loop.json @@ -0,0 +1,2973 @@ +{ + "description": "tests that operations respect overload backoff retry loop", + "schemaVersion": "1.3", + "runOnRequirements": [ + { + "minServerVersion": "4.4", + "topologies": [ + "replicaset", + "sharded", + "load-balanced" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "client", + "useMultipleMongoses": false, + "observeEvents": [ + "commandStartedEvent", + "commandSucceededEvent", + "commandFailedEvent" + ] + } + }, + { + "client": { + "id": "internal_client", + "useMultipleMongoses": false + } + }, + { + "database": { + "id": "database", + "client": "internal_client", + "databaseName": "retryable-writes-tests" + } + }, + { + "collection": { + "id": "retryable-writes-tests", + "database": "database", + "collectionName": "coll" + } + }, + { + "database": { + "id": "database", + "client": "client", + "databaseName": "retryable-writes-tests" + } + }, + { + "collection": { + "id": "collection", + "database": "database", + "collectionName": "coll" + } + } + ], + "tests": [ + { + "description": "client.listDatabases retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "listDatabases" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "client", + "name": "listDatabases", + "arguments": { + "filter": {} + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandFailedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandStartedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandFailedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandStartedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandFailedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandStartedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandSucceededEvent": { + "commandName": "listDatabases" + } + } + ] + } + ] + }, + { + "description": "client.listDatabaseNames retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "listDatabases" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "client", + "name": "listDatabaseNames" + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandFailedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandStartedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandFailedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandStartedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandFailedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandStartedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandSucceededEvent": { + "commandName": "listDatabases" + } + } + ] + } + ] + }, + { + "description": "client.createChangeStream retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "client", + "name": "createChangeStream", + "arguments": { + "pipeline": [] + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandSucceededEvent": { + "commandName": "aggregate" + } + } + ] + } + ] + }, + { + "description": "client.clientBulkWrite retries using operation loop", + "runOnRequirements": [ + { + "minServerVersion": "8.0" + } + ], + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "bulkWrite" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "client", + "name": "clientBulkWrite", + "arguments": { + "models": [ + { + "insertOne": { + "namespace": "retryable-writes-tests.coll", + "document": { + "_id": 8, + "x": 88 + } + } + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "bulkWrite" + } + }, + { + "commandFailedEvent": { + "commandName": "bulkWrite" + } + }, + { + "commandStartedEvent": { + "commandName": "bulkWrite" + } + }, + { + "commandFailedEvent": { + "commandName": "bulkWrite" + } + }, + { + "commandStartedEvent": { + "commandName": "bulkWrite" + } + }, + { + "commandFailedEvent": { + "commandName": "bulkWrite" + } + }, + { + "commandStartedEvent": { + "commandName": "bulkWrite" + } + }, + { + "commandSucceededEvent": { + "commandName": "bulkWrite" + } + } + ] + } + ] + }, + { + "description": "database.aggregate retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "database", + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$listLocalSessions": {} + }, + { + "$limit": 1 + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandSucceededEvent": { + "commandName": "aggregate" + } + } + ] + } + ] + }, + { + "description": "database.listCollections retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "listCollections" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "database", + "name": "listCollections", + "arguments": { + "filter": {} + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "listCollections" + } + }, + { + "commandFailedEvent": { + "commandName": "listCollections" + } + }, + { + "commandStartedEvent": { + "commandName": "listCollections" + } + }, + { + "commandFailedEvent": { + "commandName": "listCollections" + } + }, + { + "commandStartedEvent": { + "commandName": "listCollections" + } + }, + { + "commandFailedEvent": { + "commandName": "listCollections" + } + }, + { + "commandStartedEvent": { + "commandName": "listCollections" + } + }, + { + "commandSucceededEvent": { + "commandName": "listCollections" + } + } + ] + } + ] + }, + { + "description": "database.listCollectionNames retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "listCollections" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "database", + "name": "listCollectionNames", + "arguments": { + "filter": {} + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "listCollections" + } + }, + { + "commandFailedEvent": { + "commandName": "listCollections" + } + }, + { + "commandStartedEvent": { + "commandName": "listCollections" + } + }, + { + "commandFailedEvent": { + "commandName": "listCollections" + } + }, + { + "commandStartedEvent": { + "commandName": "listCollections" + } + }, + { + "commandFailedEvent": { + "commandName": "listCollections" + } + }, + { + "commandStartedEvent": { + "commandName": "listCollections" + } + }, + { + "commandSucceededEvent": { + "commandName": "listCollections" + } + } + ] + } + ] + }, + { + "description": "database.runCommand retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "ping" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "database", + "name": "runCommand", + "arguments": { + "command": { + "ping": 1 + }, + "commandName": "ping" + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "ping" + } + }, + { + "commandFailedEvent": { + "commandName": "ping" + } + }, + { + "commandStartedEvent": { + "commandName": "ping" + } + }, + { + "commandFailedEvent": { + "commandName": "ping" + } + }, + { + "commandStartedEvent": { + "commandName": "ping" + } + }, + { + "commandFailedEvent": { + "commandName": "ping" + } + }, + { + "commandStartedEvent": { + "commandName": "ping" + } + }, + { + "commandSucceededEvent": { + "commandName": "ping" + } + } + ] + } + ] + }, + { + "description": "database.createChangeStream retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "database", + "name": "createChangeStream", + "arguments": { + "pipeline": [] + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandSucceededEvent": { + "commandName": "aggregate" + } + } + ] + } + ] + }, + { + "description": "collection.aggregate retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "aggregate", + "arguments": { + "pipeline": [] + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandSucceededEvent": { + "commandName": "aggregate" + } + } + ] + } + ] + }, + { + "description": "collection.countDocuments retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "countDocuments", + "arguments": { + "filter": {} + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandSucceededEvent": { + "commandName": "aggregate" + } + } + ] + } + ] + }, + { + "description": "collection.estimatedDocumentCount retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "count" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "estimatedDocumentCount" + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "count" + } + }, + { + "commandFailedEvent": { + "commandName": "count" + } + }, + { + "commandStartedEvent": { + "commandName": "count" + } + }, + { + "commandFailedEvent": { + "commandName": "count" + } + }, + { + "commandStartedEvent": { + "commandName": "count" + } + }, + { + "commandFailedEvent": { + "commandName": "count" + } + }, + { + "commandStartedEvent": { + "commandName": "count" + } + }, + { + "commandSucceededEvent": { + "commandName": "count" + } + } + ] + } + ] + }, + { + "description": "collection.distinct retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "distinct" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "distinct", + "arguments": { + "fieldName": "x", + "filter": {} + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "distinct" + } + }, + { + "commandFailedEvent": { + "commandName": "distinct" + } + }, + { + "commandStartedEvent": { + "commandName": "distinct" + } + }, + { + "commandFailedEvent": { + "commandName": "distinct" + } + }, + { + "commandStartedEvent": { + "commandName": "distinct" + } + }, + { + "commandFailedEvent": { + "commandName": "distinct" + } + }, + { + "commandStartedEvent": { + "commandName": "distinct" + } + }, + { + "commandSucceededEvent": { + "commandName": "distinct" + } + } + ] + } + ] + }, + { + "description": "collection.find retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "find" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "find", + "arguments": { + "filter": {} + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandFailedEvent": { + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandFailedEvent": { + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandFailedEvent": { + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandSucceededEvent": { + "commandName": "find" + } + } + ] + } + ] + }, + { + "description": "collection.findOne retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "find" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "findOne", + "arguments": { + "filter": {} + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandFailedEvent": { + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandFailedEvent": { + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandFailedEvent": { + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandSucceededEvent": { + "commandName": "find" + } + } + ] + } + ] + }, + { + "description": "collection.listIndexes retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "listIndexes" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "listIndexes" + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandSucceededEvent": { + "commandName": "listIndexes" + } + } + ] + } + ] + }, + { + "description": "collection.listIndexNames retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "listIndexes" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "listIndexNames" + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandSucceededEvent": { + "commandName": "listIndexes" + } + } + ] + } + ] + }, + { + "description": "collection.createChangeStream retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "createChangeStream", + "arguments": { + "pipeline": [] + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandSucceededEvent": { + "commandName": "aggregate" + } + } + ] + } + ] + }, + { + "description": "collection.insertOne retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "insert" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "insertOne", + "arguments": { + "document": { + "_id": 2, + "x": 22 + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandSucceededEvent": { + "commandName": "insert" + } + } + ] + } + ] + }, + { + "description": "collection.insertMany retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "insert" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "insertMany", + "arguments": { + "documents": [ + { + "_id": 2, + "x": 22 + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandSucceededEvent": { + "commandName": "insert" + } + } + ] + } + ] + }, + { + "description": "collection.deleteOne retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "delete" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "deleteOne", + "arguments": { + "filter": {} + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "delete" + } + }, + { + "commandFailedEvent": { + "commandName": "delete" + } + }, + { + "commandStartedEvent": { + "commandName": "delete" + } + }, + { + "commandFailedEvent": { + "commandName": "delete" + } + }, + { + "commandStartedEvent": { + "commandName": "delete" + } + }, + { + "commandFailedEvent": { + "commandName": "delete" + } + }, + { + "commandStartedEvent": { + "commandName": "delete" + } + }, + { + "commandSucceededEvent": { + "commandName": "delete" + } + } + ] + } + ] + }, + { + "description": "collection.deleteMany retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "delete" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "deleteMany", + "arguments": { + "filter": {} + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "delete" + } + }, + { + "commandFailedEvent": { + "commandName": "delete" + } + }, + { + "commandStartedEvent": { + "commandName": "delete" + } + }, + { + "commandFailedEvent": { + "commandName": "delete" + } + }, + { + "commandStartedEvent": { + "commandName": "delete" + } + }, + { + "commandFailedEvent": { + "commandName": "delete" + } + }, + { + "commandStartedEvent": { + "commandName": "delete" + } + }, + { + "commandSucceededEvent": { + "commandName": "delete" + } + } + ] + } + ] + }, + { + "description": "collection.replaceOne retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "update" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "replaceOne", + "arguments": { + "filter": {}, + "replacement": { + "x": 22 + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + }, + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + }, + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + }, + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandSucceededEvent": { + "commandName": "update" + } + } + ] + } + ] + }, + { + "description": "collection.updateOne retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "update" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$set": { + "x": 22 + } + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + }, + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + }, + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + }, + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandSucceededEvent": { + "commandName": "update" + } + } + ] + } + ] + }, + { + "description": "collection.updateMany retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "update" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "updateMany", + "arguments": { + "filter": {}, + "update": { + "$set": { + "x": 22 + } + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + }, + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + }, + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + }, + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandSucceededEvent": { + "commandName": "update" + } + } + ] + } + ] + }, + { + "description": "collection.findOneAndDelete retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "findAndModify" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "findOneAndDelete", + "arguments": { + "filter": {} + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandSucceededEvent": { + "commandName": "findAndModify" + } + } + ] + } + ] + }, + { + "description": "collection.findOneAndReplace retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "findAndModify" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "findOneAndReplace", + "arguments": { + "filter": {}, + "replacement": { + "x": 22 + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandSucceededEvent": { + "commandName": "findAndModify" + } + } + ] + } + ] + }, + { + "description": "collection.findOneAndUpdate retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "findAndModify" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "findOneAndUpdate", + "arguments": { + "filter": {}, + "update": { + "$set": { + "x": 22 + } + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandSucceededEvent": { + "commandName": "findAndModify" + } + } + ] + } + ] + }, + { + "description": "collection.bulkWrite retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "insert" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "insertOne": { + "document": { + "_id": 2, + "x": 22 + } + } + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandSucceededEvent": { + "commandName": "insert" + } + } + ] + } + ] + }, + { + "description": "collection.createIndex retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "createIndexes" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "createIndex", + "arguments": { + "keys": { + "x": 11 + }, + "name": "x_11" + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "createIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "createIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "createIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "createIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "createIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "createIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "createIndexes" + } + }, + { + "commandSucceededEvent": { + "commandName": "createIndexes" + } + } + ] + } + ] + }, + { + "description": "collection.dropIndex retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "object": "retryable-writes-tests", + "name": "createIndex", + "arguments": { + "keys": { + "x": 11 + }, + "name": "x_11" + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "dropIndexes" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "dropIndex", + "arguments": { + "name": "x_11" + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandSucceededEvent": { + "commandName": "dropIndexes" + } + } + ] + } + ] + }, + { + "description": "collection.dropIndexes retries using operation loop", + "operations": [ + { + "object": "retryable-writes-tests", + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "internal_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "dropIndexes" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "dropIndexes" + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandSucceededEvent": { + "commandName": "dropIndexes" + } + } + ] + } + ] + } + ] +} diff --git a/test/spec/client-backpressure/backpressure-retry-loop.yml b/test/spec/client-backpressure/backpressure-retry-loop.yml new file mode 100644 index 0000000000..a566949453 --- /dev/null +++ b/test/spec/client-backpressure/backpressure-retry-loop.yml @@ -0,0 +1,1596 @@ +# Tests in this file are generated from backpressure-retry-loop.yml.template. + +description: tests that operations respect overload backoff retry loop + +schemaVersion: '1.3' + +runOnRequirements: + - + minServerVersion: '4.4' # failCommand + topologies: [replicaset, sharded, load-balanced] + +createEntities: + - + client: + id: &client client + useMultipleMongoses: false + observeEvents: [commandStartedEvent, commandSucceededEvent, commandFailedEvent] + + - + client: + id: &internal_client internal_client + useMultipleMongoses: false + + - + database: + id: &internal_db database + client: *internal_client + databaseName: &database_name retryable-writes-tests + + - + collection: + id: &internal_collection retryable-writes-tests + database: *internal_db + collectionName: &collection_name coll + + - + database: + id: &database database + client: *client + databaseName: &database_name retryable-writes-tests + + - + collection: + id: &collection collection + database: *database + collectionName: *collection_name + +tests: + + - + description: 'client.listDatabases retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [listDatabases] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *client + name: listDatabases + arguments: + filter: {} + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: listDatabases + - commandFailedEvent: + commandName: listDatabases + - commandStartedEvent: + commandName: listDatabases + - commandFailedEvent: + commandName: listDatabases + - commandStartedEvent: + commandName: listDatabases + - commandFailedEvent: + commandName: listDatabases + - commandStartedEvent: + commandName: listDatabases + - commandSucceededEvent: + commandName: listDatabases + + - + description: 'client.listDatabaseNames retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [listDatabases] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *client + name: listDatabaseNames + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: listDatabases + - commandFailedEvent: + commandName: listDatabases + - commandStartedEvent: + commandName: listDatabases + - commandFailedEvent: + commandName: listDatabases + - commandStartedEvent: + commandName: listDatabases + - commandFailedEvent: + commandName: listDatabases + - commandStartedEvent: + commandName: listDatabases + - commandSucceededEvent: + commandName: listDatabases + + - + description: 'client.createChangeStream retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [aggregate] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *client + name: createChangeStream + arguments: + pipeline: [] + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandSucceededEvent: + commandName: aggregate + + - + description: 'client.clientBulkWrite retries using operation loop' + runOnRequirements: + - minServerVersion: '8.0' # client bulk write added to server in 8.0 + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [bulkWrite] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *client + name: clientBulkWrite + arguments: + models: + - insertOne: + namespace: retryable-writes-tests.coll + document: { _id: 8, x: 88 } + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: bulkWrite + - commandFailedEvent: + commandName: bulkWrite + - commandStartedEvent: + commandName: bulkWrite + - commandFailedEvent: + commandName: bulkWrite + - commandStartedEvent: + commandName: bulkWrite + - commandFailedEvent: + commandName: bulkWrite + - commandStartedEvent: + commandName: bulkWrite + - commandSucceededEvent: + commandName: bulkWrite + + - + description: 'database.aggregate retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [aggregate] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *database + name: aggregate + arguments: + pipeline: [ { $listLocalSessions: {} }, { $limit: 1 } ] + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandSucceededEvent: + commandName: aggregate + + - + description: 'database.listCollections retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [listCollections] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *database + name: listCollections + arguments: + filter: {} + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: listCollections + - commandFailedEvent: + commandName: listCollections + - commandStartedEvent: + commandName: listCollections + - commandFailedEvent: + commandName: listCollections + - commandStartedEvent: + commandName: listCollections + - commandFailedEvent: + commandName: listCollections + - commandStartedEvent: + commandName: listCollections + - commandSucceededEvent: + commandName: listCollections + + - + description: 'database.listCollectionNames retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [listCollections] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *database + name: listCollectionNames + arguments: + filter: {} + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: listCollections + - commandFailedEvent: + commandName: listCollections + - commandStartedEvent: + commandName: listCollections + - commandFailedEvent: + commandName: listCollections + - commandStartedEvent: + commandName: listCollections + - commandFailedEvent: + commandName: listCollections + - commandStartedEvent: + commandName: listCollections + - commandSucceededEvent: + commandName: listCollections + + - + description: 'database.runCommand retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [ping] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *database + name: runCommand + arguments: + command: { ping: 1 } + commandName: ping + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: ping + - commandFailedEvent: + commandName: ping + - commandStartedEvent: + commandName: ping + - commandFailedEvent: + commandName: ping + - commandStartedEvent: + commandName: ping + - commandFailedEvent: + commandName: ping + - commandStartedEvent: + commandName: ping + - commandSucceededEvent: + commandName: ping + + - + description: 'database.createChangeStream retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [aggregate] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *database + name: createChangeStream + arguments: + pipeline: [] + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandSucceededEvent: + commandName: aggregate + + - + description: 'collection.aggregate retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [aggregate] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: aggregate + arguments: + pipeline: [] + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandSucceededEvent: + commandName: aggregate + + - + description: 'collection.countDocuments retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [aggregate] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: countDocuments + arguments: + filter: {} + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandSucceededEvent: + commandName: aggregate + + - + description: 'collection.estimatedDocumentCount retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [count] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: estimatedDocumentCount + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: count + - commandFailedEvent: + commandName: count + - commandStartedEvent: + commandName: count + - commandFailedEvent: + commandName: count + - commandStartedEvent: + commandName: count + - commandFailedEvent: + commandName: count + - commandStartedEvent: + commandName: count + - commandSucceededEvent: + commandName: count + + - + description: 'collection.distinct retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [distinct] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: distinct + arguments: + fieldName: x + filter: {} + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: distinct + - commandFailedEvent: + commandName: distinct + - commandStartedEvent: + commandName: distinct + - commandFailedEvent: + commandName: distinct + - commandStartedEvent: + commandName: distinct + - commandFailedEvent: + commandName: distinct + - commandStartedEvent: + commandName: distinct + - commandSucceededEvent: + commandName: distinct + + - + description: 'collection.find retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [find] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: find + arguments: + filter: {} + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: find + - commandFailedEvent: + commandName: find + - commandStartedEvent: + commandName: find + - commandFailedEvent: + commandName: find + - commandStartedEvent: + commandName: find + - commandFailedEvent: + commandName: find + - commandStartedEvent: + commandName: find + - commandSucceededEvent: + commandName: find + + - + description: 'collection.findOne retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [find] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: findOne + arguments: + filter: {} + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: find + - commandFailedEvent: + commandName: find + - commandStartedEvent: + commandName: find + - commandFailedEvent: + commandName: find + - commandStartedEvent: + commandName: find + - commandFailedEvent: + commandName: find + - commandStartedEvent: + commandName: find + - commandSucceededEvent: + commandName: find + + - + description: 'collection.listIndexes retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [listIndexes] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: listIndexes + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: listIndexes + - commandFailedEvent: + commandName: listIndexes + - commandStartedEvent: + commandName: listIndexes + - commandFailedEvent: + commandName: listIndexes + - commandStartedEvent: + commandName: listIndexes + - commandFailedEvent: + commandName: listIndexes + - commandStartedEvent: + commandName: listIndexes + - commandSucceededEvent: + commandName: listIndexes + + - + description: 'collection.listIndexNames retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [listIndexes] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: listIndexNames + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: listIndexes + - commandFailedEvent: + commandName: listIndexes + - commandStartedEvent: + commandName: listIndexes + - commandFailedEvent: + commandName: listIndexes + - commandStartedEvent: + commandName: listIndexes + - commandFailedEvent: + commandName: listIndexes + - commandStartedEvent: + commandName: listIndexes + - commandSucceededEvent: + commandName: listIndexes + + - + description: 'collection.createChangeStream retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [aggregate] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: createChangeStream + arguments: + pipeline: [] + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandSucceededEvent: + commandName: aggregate + + - + description: 'collection.insertOne retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [insert] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: insertOne + arguments: + document: { _id: 2, x: 22 } + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandSucceededEvent: + commandName: insert + + - + description: 'collection.insertMany retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [insert] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: insertMany + arguments: + documents: + - { _id: 2, x: 22 } + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandSucceededEvent: + commandName: insert + + - + description: 'collection.deleteOne retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [delete] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: deleteOne + arguments: + filter: {} + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: delete + - commandFailedEvent: + commandName: delete + - commandStartedEvent: + commandName: delete + - commandFailedEvent: + commandName: delete + - commandStartedEvent: + commandName: delete + - commandFailedEvent: + commandName: delete + - commandStartedEvent: + commandName: delete + - commandSucceededEvent: + commandName: delete + + - + description: 'collection.deleteMany retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [delete] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: deleteMany + arguments: + filter: {} + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: delete + - commandFailedEvent: + commandName: delete + - commandStartedEvent: + commandName: delete + - commandFailedEvent: + commandName: delete + - commandStartedEvent: + commandName: delete + - commandFailedEvent: + commandName: delete + - commandStartedEvent: + commandName: delete + - commandSucceededEvent: + commandName: delete + + - + description: 'collection.replaceOne retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [update] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: replaceOne + arguments: + filter: {} + replacement: { x: 22 } + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + - commandStartedEvent: + commandName: update + - commandSucceededEvent: + commandName: update + + - + description: 'collection.updateOne retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [update] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: updateOne + arguments: + filter: {} + update: { $set: { x: 22 } } + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + - commandStartedEvent: + commandName: update + - commandSucceededEvent: + commandName: update + + - + description: 'collection.updateMany retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [update] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: updateMany + arguments: + filter: {} + update: { $set: { x: 22 } } + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + - commandStartedEvent: + commandName: update + - commandSucceededEvent: + commandName: update + + - + description: 'collection.findOneAndDelete retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [findAndModify] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: findOneAndDelete + arguments: + filter: {} + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + - commandStartedEvent: + commandName: findAndModify + - commandSucceededEvent: + commandName: findAndModify + + - + description: 'collection.findOneAndReplace retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [findAndModify] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: findOneAndReplace + arguments: + filter: {} + replacement: { x: 22 } + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + - commandStartedEvent: + commandName: findAndModify + - commandSucceededEvent: + commandName: findAndModify + + - + description: 'collection.findOneAndUpdate retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [findAndModify] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: findOneAndUpdate + arguments: + filter: {} + update: { $set: { x: 22 } } + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + - commandStartedEvent: + commandName: findAndModify + - commandSucceededEvent: + commandName: findAndModify + + - + description: 'collection.bulkWrite retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [insert] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: bulkWrite + arguments: + requests: + - insertOne: + document: { _id: 2, x: 22 } + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandSucceededEvent: + commandName: insert + + - + description: 'collection.createIndex retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [createIndexes] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: createIndex + arguments: + keys: { x: 11 } + name: "x_11" + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: createIndexes + - commandFailedEvent: + commandName: createIndexes + - commandStartedEvent: + commandName: createIndexes + - commandFailedEvent: + commandName: createIndexes + - commandStartedEvent: + commandName: createIndexes + - commandFailedEvent: + commandName: createIndexes + - commandStartedEvent: + commandName: createIndexes + - commandSucceededEvent: + commandName: createIndexes + + - + description: 'collection.dropIndex retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + - + object: *internal_collection + name: createIndex + arguments: + keys: { x: 11 } + name: "x_11" + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [dropIndexes] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: dropIndex + arguments: + name: "x_11" + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: dropIndexes + - commandFailedEvent: + commandName: dropIndexes + - commandStartedEvent: + commandName: dropIndexes + - commandFailedEvent: + commandName: dropIndexes + - commandStartedEvent: + commandName: dropIndexes + - commandFailedEvent: + commandName: dropIndexes + - commandStartedEvent: + commandName: dropIndexes + - commandSucceededEvent: + commandName: dropIndexes + + - + description: 'collection.dropIndexes retries using operation loop' + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [dropIndexes] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: dropIndexes + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: dropIndexes + - commandFailedEvent: + commandName: dropIndexes + - commandStartedEvent: + commandName: dropIndexes + - commandFailedEvent: + commandName: dropIndexes + - commandStartedEvent: + commandName: dropIndexes + - commandFailedEvent: + commandName: dropIndexes + - commandStartedEvent: + commandName: dropIndexes + - commandSucceededEvent: + commandName: dropIndexes diff --git a/test/spec/client-backpressure/backpressure-retry-loop.yml.template b/test/spec/client-backpressure/backpressure-retry-loop.yml.template new file mode 100644 index 0000000000..ac47783e53 --- /dev/null +++ b/test/spec/client-backpressure/backpressure-retry-loop.yml.template @@ -0,0 +1,114 @@ +# Tests in this file are generated from backpressure-retry-loop.yml.template. + +description: tests that operations respect overload backoff retry loop + +schemaVersion: '1.3' + +runOnRequirements: + - + minServerVersion: '4.4' # failCommand + topologies: [replicaset, sharded, load-balanced] + +createEntities: + - + client: + id: &client client + useMultipleMongoses: false + observeEvents: [commandStartedEvent, commandSucceededEvent, commandFailedEvent] + + - + client: + id: &internal_client internal_client + useMultipleMongoses: false + + - + database: + id: &internal_db database + client: *internal_client + databaseName: &database_name retryable-writes-tests + + - + collection: + id: &internal_collection retryable-writes-tests + database: *internal_db + collectionName: &collection_name coll + + - + database: + id: &database database + client: *client + databaseName: &database_name retryable-writes-tests + + - + collection: + id: &collection collection + database: *database + collectionName: *collection_name + +tests: +{% for operation in operations %} + - + description: '{{operation.object}}.{{operation.operation_name}} retries using operation loop' + {%- if ((operation.operation_name == 'clientBulkWrite')) %} + runOnRequirements: + - minServerVersion: '8.0' # client bulk write added to server in 8.0 + {%- endif %} + operations: + - + object: *internal_collection + name: deleteMany + arguments: + filter: {} + + {%- if operation.operation_name == "dropIndex" %} + - + object: *internal_collection + name: createIndex + arguments: + keys: { x: 11 } + name: "x_11" + {%- endif %} + + + - name: failPoint + object: testRunner + arguments: + client: *internal_client + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [{{operation.command_name}}] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *{{operation.object}} + name: {{operation.operation_name}} + {%- if operation.arguments|length > 0 %} + arguments: + {%- for arg in operation.arguments %} + {{arg}} + {%- endfor -%} + {%- endif %} + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: {{operation.command_name}} + - commandFailedEvent: + commandName: {{operation.command_name}} + - commandStartedEvent: + commandName: {{operation.command_name}} + - commandFailedEvent: + commandName: {{operation.command_name}} + - commandStartedEvent: + commandName: {{operation.command_name}} + - commandFailedEvent: + commandName: {{operation.command_name}} + - commandStartedEvent: + commandName: {{operation.command_name}} + - commandSucceededEvent: + commandName: {{operation.command_name}} +{% endfor -%} diff --git a/test/spec/client-backpressure/backpressure-retry-max-attempts.json b/test/spec/client-backpressure/backpressure-retry-max-attempts.json new file mode 100644 index 0000000000..0cd52e9a53 --- /dev/null +++ b/test/spec/client-backpressure/backpressure-retry-max-attempts.json @@ -0,0 +1,3445 @@ +{ + "description": "tests that operations retry at most maxAttempts=5 times", + "schemaVersion": "1.3", + "runOnRequirements": [ + { + "minServerVersion": "4.4", + "topologies": [ + "replicaset", + "sharded", + "load-balanced" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "client", + "useMultipleMongoses": false, + "observeEvents": [ + "commandStartedEvent", + "commandSucceededEvent", + "commandFailedEvent" + ] + } + }, + { + "client": { + "id": "fail_point_client", + "useMultipleMongoses": false + } + }, + { + "database": { + "id": "database", + "client": "client", + "databaseName": "retryable-writes-tests" + } + }, + { + "collection": { + "id": "collection", + "database": "database", + "collectionName": "coll" + } + } + ], + "initialData": [ + { + "collectionName": "coll", + "databaseName": "retryable-writes-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "client.listDatabases retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "listDatabases" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "client", + "name": "listDatabases", + "arguments": { + "filter": {} + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandFailedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandStartedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandFailedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandStartedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandFailedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandStartedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandFailedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandStartedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandFailedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandStartedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandFailedEvent": { + "commandName": "listDatabases" + } + } + ] + } + ] + }, + { + "description": "client.listDatabaseNames retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "listDatabases" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "client", + "name": "listDatabaseNames", + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandFailedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandStartedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandFailedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandStartedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandFailedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandStartedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandFailedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandStartedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandFailedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandStartedEvent": { + "commandName": "listDatabases" + } + }, + { + "commandFailedEvent": { + "commandName": "listDatabases" + } + } + ] + } + ] + }, + { + "description": "client.createChangeStream retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "aggregate" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "client", + "name": "createChangeStream", + "arguments": { + "pipeline": [] + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + } + ] + } + ] + }, + { + "description": "client.clientBulkWrite retries at most maxAttempts=5 times", + "runOnRequirements": [ + { + "minServerVersion": "8.0" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "bulkWrite" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "client", + "name": "clientBulkWrite", + "arguments": { + "models": [ + { + "insertOne": { + "namespace": "retryable-writes-tests.coll", + "document": { + "_id": 8, + "x": 88 + } + } + } + ] + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "bulkWrite" + } + }, + { + "commandFailedEvent": { + "commandName": "bulkWrite" + } + }, + { + "commandStartedEvent": { + "commandName": "bulkWrite" + } + }, + { + "commandFailedEvent": { + "commandName": "bulkWrite" + } + }, + { + "commandStartedEvent": { + "commandName": "bulkWrite" + } + }, + { + "commandFailedEvent": { + "commandName": "bulkWrite" + } + }, + { + "commandStartedEvent": { + "commandName": "bulkWrite" + } + }, + { + "commandFailedEvent": { + "commandName": "bulkWrite" + } + }, + { + "commandStartedEvent": { + "commandName": "bulkWrite" + } + }, + { + "commandFailedEvent": { + "commandName": "bulkWrite" + } + }, + { + "commandStartedEvent": { + "commandName": "bulkWrite" + } + }, + { + "commandFailedEvent": { + "commandName": "bulkWrite" + } + } + ] + } + ] + }, + { + "description": "database.aggregate retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "aggregate" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "database", + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$listLocalSessions": {} + }, + { + "$limit": 1 + } + ] + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + } + ] + } + ] + }, + { + "description": "database.listCollections retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "listCollections" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "database", + "name": "listCollections", + "arguments": { + "filter": {} + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "listCollections" + } + }, + { + "commandFailedEvent": { + "commandName": "listCollections" + } + }, + { + "commandStartedEvent": { + "commandName": "listCollections" + } + }, + { + "commandFailedEvent": { + "commandName": "listCollections" + } + }, + { + "commandStartedEvent": { + "commandName": "listCollections" + } + }, + { + "commandFailedEvent": { + "commandName": "listCollections" + } + }, + { + "commandStartedEvent": { + "commandName": "listCollections" + } + }, + { + "commandFailedEvent": { + "commandName": "listCollections" + } + }, + { + "commandStartedEvent": { + "commandName": "listCollections" + } + }, + { + "commandFailedEvent": { + "commandName": "listCollections" + } + }, + { + "commandStartedEvent": { + "commandName": "listCollections" + } + }, + { + "commandFailedEvent": { + "commandName": "listCollections" + } + } + ] + } + ] + }, + { + "description": "database.listCollectionNames retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "listCollections" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "database", + "name": "listCollectionNames", + "arguments": { + "filter": {} + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "listCollections" + } + }, + { + "commandFailedEvent": { + "commandName": "listCollections" + } + }, + { + "commandStartedEvent": { + "commandName": "listCollections" + } + }, + { + "commandFailedEvent": { + "commandName": "listCollections" + } + }, + { + "commandStartedEvent": { + "commandName": "listCollections" + } + }, + { + "commandFailedEvent": { + "commandName": "listCollections" + } + }, + { + "commandStartedEvent": { + "commandName": "listCollections" + } + }, + { + "commandFailedEvent": { + "commandName": "listCollections" + } + }, + { + "commandStartedEvent": { + "commandName": "listCollections" + } + }, + { + "commandFailedEvent": { + "commandName": "listCollections" + } + }, + { + "commandStartedEvent": { + "commandName": "listCollections" + } + }, + { + "commandFailedEvent": { + "commandName": "listCollections" + } + } + ] + } + ] + }, + { + "description": "database.runCommand retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "ping" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "database", + "name": "runCommand", + "arguments": { + "command": { + "ping": 1 + }, + "commandName": "ping" + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "ping" + } + }, + { + "commandFailedEvent": { + "commandName": "ping" + } + }, + { + "commandStartedEvent": { + "commandName": "ping" + } + }, + { + "commandFailedEvent": { + "commandName": "ping" + } + }, + { + "commandStartedEvent": { + "commandName": "ping" + } + }, + { + "commandFailedEvent": { + "commandName": "ping" + } + }, + { + "commandStartedEvent": { + "commandName": "ping" + } + }, + { + "commandFailedEvent": { + "commandName": "ping" + } + }, + { + "commandStartedEvent": { + "commandName": "ping" + } + }, + { + "commandFailedEvent": { + "commandName": "ping" + } + }, + { + "commandStartedEvent": { + "commandName": "ping" + } + }, + { + "commandFailedEvent": { + "commandName": "ping" + } + } + ] + } + ] + }, + { + "description": "database.createChangeStream retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "aggregate" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "database", + "name": "createChangeStream", + "arguments": { + "pipeline": [] + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + } + ] + } + ] + }, + { + "description": "collection.aggregate retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "aggregate" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "aggregate", + "arguments": { + "pipeline": [] + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + } + ] + } + ] + }, + { + "description": "collection.countDocuments retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "aggregate" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "countDocuments", + "arguments": { + "filter": {} + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + } + ] + } + ] + }, + { + "description": "collection.estimatedDocumentCount retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "count" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "estimatedDocumentCount", + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "count" + } + }, + { + "commandFailedEvent": { + "commandName": "count" + } + }, + { + "commandStartedEvent": { + "commandName": "count" + } + }, + { + "commandFailedEvent": { + "commandName": "count" + } + }, + { + "commandStartedEvent": { + "commandName": "count" + } + }, + { + "commandFailedEvent": { + "commandName": "count" + } + }, + { + "commandStartedEvent": { + "commandName": "count" + } + }, + { + "commandFailedEvent": { + "commandName": "count" + } + }, + { + "commandStartedEvent": { + "commandName": "count" + } + }, + { + "commandFailedEvent": { + "commandName": "count" + } + }, + { + "commandStartedEvent": { + "commandName": "count" + } + }, + { + "commandFailedEvent": { + "commandName": "count" + } + } + ] + } + ] + }, + { + "description": "collection.distinct retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "distinct" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "distinct", + "arguments": { + "fieldName": "x", + "filter": {} + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "distinct" + } + }, + { + "commandFailedEvent": { + "commandName": "distinct" + } + }, + { + "commandStartedEvent": { + "commandName": "distinct" + } + }, + { + "commandFailedEvent": { + "commandName": "distinct" + } + }, + { + "commandStartedEvent": { + "commandName": "distinct" + } + }, + { + "commandFailedEvent": { + "commandName": "distinct" + } + }, + { + "commandStartedEvent": { + "commandName": "distinct" + } + }, + { + "commandFailedEvent": { + "commandName": "distinct" + } + }, + { + "commandStartedEvent": { + "commandName": "distinct" + } + }, + { + "commandFailedEvent": { + "commandName": "distinct" + } + }, + { + "commandStartedEvent": { + "commandName": "distinct" + } + }, + { + "commandFailedEvent": { + "commandName": "distinct" + } + } + ] + } + ] + }, + { + "description": "collection.find retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "find" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "find", + "arguments": { + "filter": {} + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandFailedEvent": { + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandFailedEvent": { + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandFailedEvent": { + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandFailedEvent": { + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandFailedEvent": { + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandFailedEvent": { + "commandName": "find" + } + } + ] + } + ] + }, + { + "description": "collection.findOne retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "find" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "findOne", + "arguments": { + "filter": {} + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandFailedEvent": { + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandFailedEvent": { + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandFailedEvent": { + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandFailedEvent": { + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandFailedEvent": { + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandFailedEvent": { + "commandName": "find" + } + } + ] + } + ] + }, + { + "description": "collection.listIndexes retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "listIndexes" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "listIndexes", + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "listIndexes" + } + } + ] + } + ] + }, + { + "description": "collection.listIndexNames retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "listIndexes" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "listIndexNames", + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "listIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "listIndexes" + } + } + ] + } + ] + }, + { + "description": "collection.createChangeStream retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "aggregate" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "createChangeStream", + "arguments": { + "pipeline": [] + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + } + ] + } + ] + }, + { + "description": "collection.insertOne retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "insert" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "insertOne", + "arguments": { + "document": { + "_id": 2, + "x": 22 + } + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + } + ] + } + ] + }, + { + "description": "collection.insertMany retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "insert" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "insertMany", + "arguments": { + "documents": [ + { + "_id": 2, + "x": 22 + } + ] + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + } + ] + } + ] + }, + { + "description": "collection.deleteOne retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "delete" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "deleteOne", + "arguments": { + "filter": {} + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "delete" + } + }, + { + "commandFailedEvent": { + "commandName": "delete" + } + }, + { + "commandStartedEvent": { + "commandName": "delete" + } + }, + { + "commandFailedEvent": { + "commandName": "delete" + } + }, + { + "commandStartedEvent": { + "commandName": "delete" + } + }, + { + "commandFailedEvent": { + "commandName": "delete" + } + }, + { + "commandStartedEvent": { + "commandName": "delete" + } + }, + { + "commandFailedEvent": { + "commandName": "delete" + } + }, + { + "commandStartedEvent": { + "commandName": "delete" + } + }, + { + "commandFailedEvent": { + "commandName": "delete" + } + }, + { + "commandStartedEvent": { + "commandName": "delete" + } + }, + { + "commandFailedEvent": { + "commandName": "delete" + } + } + ] + } + ] + }, + { + "description": "collection.deleteMany retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "delete" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "deleteMany", + "arguments": { + "filter": {} + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "delete" + } + }, + { + "commandFailedEvent": { + "commandName": "delete" + } + }, + { + "commandStartedEvent": { + "commandName": "delete" + } + }, + { + "commandFailedEvent": { + "commandName": "delete" + } + }, + { + "commandStartedEvent": { + "commandName": "delete" + } + }, + { + "commandFailedEvent": { + "commandName": "delete" + } + }, + { + "commandStartedEvent": { + "commandName": "delete" + } + }, + { + "commandFailedEvent": { + "commandName": "delete" + } + }, + { + "commandStartedEvent": { + "commandName": "delete" + } + }, + { + "commandFailedEvent": { + "commandName": "delete" + } + }, + { + "commandStartedEvent": { + "commandName": "delete" + } + }, + { + "commandFailedEvent": { + "commandName": "delete" + } + } + ] + } + ] + }, + { + "description": "collection.replaceOne retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "update" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "replaceOne", + "arguments": { + "filter": {}, + "replacement": { + "x": 22 + } + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + }, + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + }, + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + }, + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + }, + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + }, + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + } + ] + } + ] + }, + { + "description": "collection.updateOne retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "update" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "updateOne", + "arguments": { + "filter": {}, + "update": { + "$set": { + "x": 22 + } + } + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + }, + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + }, + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + }, + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + }, + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + }, + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + } + ] + } + ] + }, + { + "description": "collection.updateMany retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "update" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "updateMany", + "arguments": { + "filter": {}, + "update": { + "$set": { + "x": 22 + } + } + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + }, + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + }, + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + }, + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + }, + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + }, + { + "commandStartedEvent": { + "commandName": "update" + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + } + ] + } + ] + }, + { + "description": "collection.findOneAndDelete retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "findAndModify" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "findOneAndDelete", + "arguments": { + "filter": {} + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + } + ] + } + ] + }, + { + "description": "collection.findOneAndReplace retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "findAndModify" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "findOneAndReplace", + "arguments": { + "filter": {}, + "replacement": { + "x": 22 + } + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + } + ] + } + ] + }, + { + "description": "collection.findOneAndUpdate retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "findAndModify" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "findOneAndUpdate", + "arguments": { + "filter": {}, + "update": { + "$set": { + "x": 22 + } + } + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandStartedEvent": { + "commandName": "findAndModify" + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + } + ] + } + ] + }, + { + "description": "collection.bulkWrite retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "insert" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "insertOne": { + "document": { + "_id": 2, + "x": 22 + } + } + } + ] + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + } + ] + } + ] + }, + { + "description": "collection.createIndex retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "createIndexes" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "createIndex", + "arguments": { + "keys": { + "x": 11 + }, + "name": "x_11" + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "createIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "createIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "createIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "createIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "createIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "createIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "createIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "createIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "createIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "createIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "createIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "createIndexes" + } + } + ] + } + ] + }, + { + "description": "collection.dropIndex retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "dropIndexes" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "dropIndex", + "arguments": { + "name": "x_11" + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "dropIndexes" + } + } + ] + } + ] + }, + { + "description": "collection.dropIndexes retries at most maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "fail_point_client", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "dropIndexes" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "object": "collection", + "name": "dropIndexes", + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandStartedEvent": { + "commandName": "dropIndexes" + } + }, + { + "commandFailedEvent": { + "commandName": "dropIndexes" + } + } + ] + } + ] + } + ] +} diff --git a/test/spec/client-backpressure/backpressure-retry-max-attempts.yml b/test/spec/client-backpressure/backpressure-retry-max-attempts.yml new file mode 100644 index 0000000000..05da92d671 --- /dev/null +++ b/test/spec/client-backpressure/backpressure-retry-max-attempts.yml @@ -0,0 +1,1841 @@ +# Tests in this file are generated from backpressure-retry-max-attempts.yml.template. + +description: tests that operations retry at most maxAttempts=5 times + +schemaVersion: '1.3' + +runOnRequirements: + - + minServerVersion: '4.4' # failCommand + topologies: [replicaset, sharded, load-balanced] + +createEntities: + - + client: + id: &client client + useMultipleMongoses: false + observeEvents: [commandStartedEvent, commandSucceededEvent, commandFailedEvent] + + - + client: + id: &fail_point_client fail_point_client + useMultipleMongoses: false + + - + database: + id: &database database + client: *client + databaseName: &database_name retryable-writes-tests + - + collection: + id: &collection collection + database: *database + collectionName: &collection_name coll + +initialData: + - + collectionName: *collection_name + databaseName: *database_name + documents: + - { _id: 1, x: 11 } + - { _id: 2, x: 22 } + +tests: + + - + description: 'client.listDatabases retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [listDatabases] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *client + name: listDatabases + arguments: + filter: {} + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: listDatabases + - commandFailedEvent: + commandName: listDatabases + - commandStartedEvent: + commandName: listDatabases + - commandFailedEvent: + commandName: listDatabases + - commandStartedEvent: + commandName: listDatabases + - commandFailedEvent: + commandName: listDatabases + - commandStartedEvent: + commandName: listDatabases + - commandFailedEvent: + commandName: listDatabases + - commandStartedEvent: + commandName: listDatabases + - commandFailedEvent: + commandName: listDatabases + - commandStartedEvent: + commandName: listDatabases + - commandFailedEvent: + commandName: listDatabases + + + - + description: 'client.listDatabaseNames retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [listDatabases] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *client + name: listDatabaseNames + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: listDatabases + - commandFailedEvent: + commandName: listDatabases + - commandStartedEvent: + commandName: listDatabases + - commandFailedEvent: + commandName: listDatabases + - commandStartedEvent: + commandName: listDatabases + - commandFailedEvent: + commandName: listDatabases + - commandStartedEvent: + commandName: listDatabases + - commandFailedEvent: + commandName: listDatabases + - commandStartedEvent: + commandName: listDatabases + - commandFailedEvent: + commandName: listDatabases + - commandStartedEvent: + commandName: listDatabases + - commandFailedEvent: + commandName: listDatabases + + + - + description: 'client.createChangeStream retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [aggregate] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *client + name: createChangeStream + arguments: + pipeline: [] + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + + + - + description: 'client.clientBulkWrite retries at most maxAttempts=5 times' + runOnRequirements: + - minServerVersion: '8.0' # client bulk write added to server in 8.0 + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [bulkWrite] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *client + name: clientBulkWrite + arguments: + models: + - insertOne: + namespace: retryable-writes-tests.coll + document: { _id: 8, x: 88 } + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: bulkWrite + - commandFailedEvent: + commandName: bulkWrite + - commandStartedEvent: + commandName: bulkWrite + - commandFailedEvent: + commandName: bulkWrite + - commandStartedEvent: + commandName: bulkWrite + - commandFailedEvent: + commandName: bulkWrite + - commandStartedEvent: + commandName: bulkWrite + - commandFailedEvent: + commandName: bulkWrite + - commandStartedEvent: + commandName: bulkWrite + - commandFailedEvent: + commandName: bulkWrite + - commandStartedEvent: + commandName: bulkWrite + - commandFailedEvent: + commandName: bulkWrite + + + - + description: 'database.aggregate retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [aggregate] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *database + name: aggregate + arguments: + pipeline: [ { $listLocalSessions: {} }, { $limit: 1 } ] + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + + + - + description: 'database.listCollections retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [listCollections] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *database + name: listCollections + arguments: + filter: {} + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: listCollections + - commandFailedEvent: + commandName: listCollections + - commandStartedEvent: + commandName: listCollections + - commandFailedEvent: + commandName: listCollections + - commandStartedEvent: + commandName: listCollections + - commandFailedEvent: + commandName: listCollections + - commandStartedEvent: + commandName: listCollections + - commandFailedEvent: + commandName: listCollections + - commandStartedEvent: + commandName: listCollections + - commandFailedEvent: + commandName: listCollections + - commandStartedEvent: + commandName: listCollections + - commandFailedEvent: + commandName: listCollections + + + - + description: 'database.listCollectionNames retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [listCollections] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *database + name: listCollectionNames + arguments: + filter: {} + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: listCollections + - commandFailedEvent: + commandName: listCollections + - commandStartedEvent: + commandName: listCollections + - commandFailedEvent: + commandName: listCollections + - commandStartedEvent: + commandName: listCollections + - commandFailedEvent: + commandName: listCollections + - commandStartedEvent: + commandName: listCollections + - commandFailedEvent: + commandName: listCollections + - commandStartedEvent: + commandName: listCollections + - commandFailedEvent: + commandName: listCollections + - commandStartedEvent: + commandName: listCollections + - commandFailedEvent: + commandName: listCollections + + + - + description: 'database.runCommand retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [ping] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *database + name: runCommand + arguments: + command: { ping: 1 } + commandName: ping + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: ping + - commandFailedEvent: + commandName: ping + - commandStartedEvent: + commandName: ping + - commandFailedEvent: + commandName: ping + - commandStartedEvent: + commandName: ping + - commandFailedEvent: + commandName: ping + - commandStartedEvent: + commandName: ping + - commandFailedEvent: + commandName: ping + - commandStartedEvent: + commandName: ping + - commandFailedEvent: + commandName: ping + - commandStartedEvent: + commandName: ping + - commandFailedEvent: + commandName: ping + + + - + description: 'database.createChangeStream retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [aggregate] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *database + name: createChangeStream + arguments: + pipeline: [] + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + + + - + description: 'collection.aggregate retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [aggregate] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: aggregate + arguments: + pipeline: [] + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + + + - + description: 'collection.countDocuments retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [aggregate] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: countDocuments + arguments: + filter: {} + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + + + - + description: 'collection.estimatedDocumentCount retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [count] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: estimatedDocumentCount + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: count + - commandFailedEvent: + commandName: count + - commandStartedEvent: + commandName: count + - commandFailedEvent: + commandName: count + - commandStartedEvent: + commandName: count + - commandFailedEvent: + commandName: count + - commandStartedEvent: + commandName: count + - commandFailedEvent: + commandName: count + - commandStartedEvent: + commandName: count + - commandFailedEvent: + commandName: count + - commandStartedEvent: + commandName: count + - commandFailedEvent: + commandName: count + + + - + description: 'collection.distinct retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [distinct] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: distinct + arguments: + fieldName: x + filter: {} + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: distinct + - commandFailedEvent: + commandName: distinct + - commandStartedEvent: + commandName: distinct + - commandFailedEvent: + commandName: distinct + - commandStartedEvent: + commandName: distinct + - commandFailedEvent: + commandName: distinct + - commandStartedEvent: + commandName: distinct + - commandFailedEvent: + commandName: distinct + - commandStartedEvent: + commandName: distinct + - commandFailedEvent: + commandName: distinct + - commandStartedEvent: + commandName: distinct + - commandFailedEvent: + commandName: distinct + + + - + description: 'collection.find retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [find] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: find + arguments: + filter: {} + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: find + - commandFailedEvent: + commandName: find + - commandStartedEvent: + commandName: find + - commandFailedEvent: + commandName: find + - commandStartedEvent: + commandName: find + - commandFailedEvent: + commandName: find + - commandStartedEvent: + commandName: find + - commandFailedEvent: + commandName: find + - commandStartedEvent: + commandName: find + - commandFailedEvent: + commandName: find + - commandStartedEvent: + commandName: find + - commandFailedEvent: + commandName: find + + + - + description: 'collection.findOne retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [find] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: findOne + arguments: + filter: {} + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: find + - commandFailedEvent: + commandName: find + - commandStartedEvent: + commandName: find + - commandFailedEvent: + commandName: find + - commandStartedEvent: + commandName: find + - commandFailedEvent: + commandName: find + - commandStartedEvent: + commandName: find + - commandFailedEvent: + commandName: find + - commandStartedEvent: + commandName: find + - commandFailedEvent: + commandName: find + - commandStartedEvent: + commandName: find + - commandFailedEvent: + commandName: find + + + - + description: 'collection.listIndexes retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [listIndexes] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: listIndexes + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: listIndexes + - commandFailedEvent: + commandName: listIndexes + - commandStartedEvent: + commandName: listIndexes + - commandFailedEvent: + commandName: listIndexes + - commandStartedEvent: + commandName: listIndexes + - commandFailedEvent: + commandName: listIndexes + - commandStartedEvent: + commandName: listIndexes + - commandFailedEvent: + commandName: listIndexes + - commandStartedEvent: + commandName: listIndexes + - commandFailedEvent: + commandName: listIndexes + - commandStartedEvent: + commandName: listIndexes + - commandFailedEvent: + commandName: listIndexes + + + - + description: 'collection.listIndexNames retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [listIndexes] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: listIndexNames + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: listIndexes + - commandFailedEvent: + commandName: listIndexes + - commandStartedEvent: + commandName: listIndexes + - commandFailedEvent: + commandName: listIndexes + - commandStartedEvent: + commandName: listIndexes + - commandFailedEvent: + commandName: listIndexes + - commandStartedEvent: + commandName: listIndexes + - commandFailedEvent: + commandName: listIndexes + - commandStartedEvent: + commandName: listIndexes + - commandFailedEvent: + commandName: listIndexes + - commandStartedEvent: + commandName: listIndexes + - commandFailedEvent: + commandName: listIndexes + + + - + description: 'collection.createChangeStream retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [aggregate] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: createChangeStream + arguments: + pipeline: [] + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + - commandStartedEvent: + commandName: aggregate + - commandFailedEvent: + commandName: aggregate + + + - + description: 'collection.insertOne retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [insert] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: insertOne + arguments: + document: { _id: 2, x: 22 } + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + + + - + description: 'collection.insertMany retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [insert] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: insertMany + arguments: + documents: + - { _id: 2, x: 22 } + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + + + - + description: 'collection.deleteOne retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [delete] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: deleteOne + arguments: + filter: {} + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: delete + - commandFailedEvent: + commandName: delete + - commandStartedEvent: + commandName: delete + - commandFailedEvent: + commandName: delete + - commandStartedEvent: + commandName: delete + - commandFailedEvent: + commandName: delete + - commandStartedEvent: + commandName: delete + - commandFailedEvent: + commandName: delete + - commandStartedEvent: + commandName: delete + - commandFailedEvent: + commandName: delete + - commandStartedEvent: + commandName: delete + - commandFailedEvent: + commandName: delete + + + - + description: 'collection.deleteMany retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [delete] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: deleteMany + arguments: + filter: {} + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: delete + - commandFailedEvent: + commandName: delete + - commandStartedEvent: + commandName: delete + - commandFailedEvent: + commandName: delete + - commandStartedEvent: + commandName: delete + - commandFailedEvent: + commandName: delete + - commandStartedEvent: + commandName: delete + - commandFailedEvent: + commandName: delete + - commandStartedEvent: + commandName: delete + - commandFailedEvent: + commandName: delete + - commandStartedEvent: + commandName: delete + - commandFailedEvent: + commandName: delete + + + - + description: 'collection.replaceOne retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [update] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: replaceOne + arguments: + filter: {} + replacement: { x: 22 } + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + + + - + description: 'collection.updateOne retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [update] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: updateOne + arguments: + filter: {} + update: { $set: { x: 22 } } + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + + + - + description: 'collection.updateMany retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [update] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: updateMany + arguments: + filter: {} + update: { $set: { x: 22 } } + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + - commandStartedEvent: + commandName: update + - commandFailedEvent: + commandName: update + + + - + description: 'collection.findOneAndDelete retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [findAndModify] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: findOneAndDelete + arguments: + filter: {} + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + + + - + description: 'collection.findOneAndReplace retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [findAndModify] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: findOneAndReplace + arguments: + filter: {} + replacement: { x: 22 } + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + + + - + description: 'collection.findOneAndUpdate retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [findAndModify] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: findOneAndUpdate + arguments: + filter: {} + update: { $set: { x: 22 } } + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + - commandStartedEvent: + commandName: findAndModify + - commandFailedEvent: + commandName: findAndModify + + + - + description: 'collection.bulkWrite retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [insert] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: bulkWrite + arguments: + requests: + - insertOne: + document: { _id: 2, x: 22 } + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandFailedEvent: + commandName: insert + + + - + description: 'collection.createIndex retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [createIndexes] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: createIndex + arguments: + keys: { x: 11 } + name: "x_11" + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: createIndexes + - commandFailedEvent: + commandName: createIndexes + - commandStartedEvent: + commandName: createIndexes + - commandFailedEvent: + commandName: createIndexes + - commandStartedEvent: + commandName: createIndexes + - commandFailedEvent: + commandName: createIndexes + - commandStartedEvent: + commandName: createIndexes + - commandFailedEvent: + commandName: createIndexes + - commandStartedEvent: + commandName: createIndexes + - commandFailedEvent: + commandName: createIndexes + - commandStartedEvent: + commandName: createIndexes + - commandFailedEvent: + commandName: createIndexes + + + - + description: 'collection.dropIndex retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [dropIndexes] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: dropIndex + arguments: + name: "x_11" + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: dropIndexes + - commandFailedEvent: + commandName: dropIndexes + - commandStartedEvent: + commandName: dropIndexes + - commandFailedEvent: + commandName: dropIndexes + - commandStartedEvent: + commandName: dropIndexes + - commandFailedEvent: + commandName: dropIndexes + - commandStartedEvent: + commandName: dropIndexes + - commandFailedEvent: + commandName: dropIndexes + - commandStartedEvent: + commandName: dropIndexes + - commandFailedEvent: + commandName: dropIndexes + - commandStartedEvent: + commandName: dropIndexes + - commandFailedEvent: + commandName: dropIndexes + + + - + description: 'collection.dropIndexes retries at most maxAttempts=5 times' + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [dropIndexes] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *collection + name: dropIndexes + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: dropIndexes + - commandFailedEvent: + commandName: dropIndexes + - commandStartedEvent: + commandName: dropIndexes + - commandFailedEvent: + commandName: dropIndexes + - commandStartedEvent: + commandName: dropIndexes + - commandFailedEvent: + commandName: dropIndexes + - commandStartedEvent: + commandName: dropIndexes + - commandFailedEvent: + commandName: dropIndexes + - commandStartedEvent: + commandName: dropIndexes + - commandFailedEvent: + commandName: dropIndexes + - commandStartedEvent: + commandName: dropIndexes + - commandFailedEvent: + commandName: dropIndexes + diff --git a/test/spec/client-backpressure/backpressure-retry-max-attempts.yml.template b/test/spec/client-backpressure/backpressure-retry-max-attempts.yml.template new file mode 100644 index 0000000000..9efbdfff19 --- /dev/null +++ b/test/spec/client-backpressure/backpressure-retry-max-attempts.yml.template @@ -0,0 +1,108 @@ +# Tests in this file are generated from backpressure-retry-max-attempts.yml.template. + +description: tests that operations retry at most maxAttempts=5 times + +schemaVersion: '1.3' + +runOnRequirements: + - + minServerVersion: '4.4' # failCommand + topologies: [replicaset, sharded, load-balanced] + +createEntities: + - + client: + id: &client client + useMultipleMongoses: false + observeEvents: [commandStartedEvent, commandSucceededEvent, commandFailedEvent] + + - + client: + id: &fail_point_client fail_point_client + useMultipleMongoses: false + + - + database: + id: &database database + client: *client + databaseName: &database_name retryable-writes-tests + - + collection: + id: &collection collection + database: *database + collectionName: &collection_name coll + +initialData: + - + collectionName: *collection_name + databaseName: *database_name + documents: + - { _id: 1, x: 11 } + - { _id: 2, x: 22 } + +tests: +{% for operation in operations %} + - + description: '{{operation.object}}.{{operation.operation_name}} retries at most maxAttempts=5 times' + {%- if ((operation.operation_name == 'clientBulkWrite')) %} + runOnRequirements: + - minServerVersion: '8.0' # client bulk write added to server in 8.0 + {%- endif %} + + operations: + - name: failPoint + object: testRunner + arguments: + client: *fail_point_client + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [{{operation.command_name}}] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - + object: *{{operation.object}} + name: {{operation.operation_name}} + {%- if operation.arguments|length > 0 %} + arguments: + {%- for arg in operation.arguments %} + {{arg}} + {%- endfor -%} + {%- endif %} + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + # we expect 6 pairs of command started and succeeded events: + # 1 initial attempt and 5 retries. + - commandStartedEvent: + commandName: {{operation.command_name}} + - commandFailedEvent: + commandName: {{operation.command_name}} + - commandStartedEvent: + commandName: {{operation.command_name}} + - commandFailedEvent: + commandName: {{operation.command_name}} + - commandStartedEvent: + commandName: {{operation.command_name}} + - commandFailedEvent: + commandName: {{operation.command_name}} + - commandStartedEvent: + commandName: {{operation.command_name}} + - commandFailedEvent: + commandName: {{operation.command_name}} + - commandStartedEvent: + commandName: {{operation.command_name}} + - commandFailedEvent: + commandName: {{operation.command_name}} + - commandStartedEvent: + commandName: {{operation.command_name}} + - commandFailedEvent: + commandName: {{operation.command_name}} + +{% endfor -%} From 6b108b7fd3e0d2545de2edc5a16b85ee86b6d342 Mon Sep 17 00:00:00 2001 From: bailey Date: Wed, 17 Dec 2025 11:00:20 -0700 Subject: [PATCH 06/12] latest changes --- src/operations/execute_operation.ts | 144 +++++++++++----------------- src/utils.ts | 20 ++-- 2 files changed, 71 insertions(+), 93 deletions(-) diff --git a/src/operations/execute_operation.ts b/src/operations/execute_operation.ts index 31f7133769..04cfb7e892 100644 --- a/src/operations/execute_operation.ts +++ b/src/operations/execute_operation.ts @@ -32,13 +32,12 @@ import { TimeoutContext } from '../timeout'; import { RETRY_COST, TOKEN_REFRESH_RATE } from '../token_bucket'; import { abortable, - exponentialBackoffDelayProvider, + ExponentialBackoffProvider, maxWireVersion, supportsRetryableWrites } from '../utils'; import { AggregateOperation } from './aggregate'; import { AbstractOperation, Aspect } from './operation'; -import { RunCommandOperation } from './run_command'; const MMAPv1_RETRY_WRITES_ERROR_CODE = MONGODB_ERROR_CODES.IllegalOperation; const MMAPv1_RETRY_WRITES_ERROR_MESSAGE = @@ -246,46 +245,48 @@ async function executeOperationWithRetries< session.incrementTransactionNumber(); } - // The maximum number of retry attempts using regular retryable reads/writes logic (not including - // SystemOverLoad error retries). - const maxNonOverloadRetryAttempts = willRetry ? (timeoutContext.csotEnabled() ? Infinity : 2) : 1; let previousOperationError: MongoError | undefined; const deprioritizedServers = new DeprioritizedServers(); - let nonOverloadRetryAttempt = 0; - let systemOverloadRetryAttempt = 0; - const maxSystemOverloadRetryAttempts = 5; - const backoffDelayProvider = exponentialBackoffDelayProvider( + const backoffDelayProvider = new ExponentialBackoffProvider( 10_000, // MAX_BACKOFF 100, // base backoff 2 // backoff rate ); - while (true) { + for ( + let attempt = 0, maxAttempts = willRetry ? (timeoutContext.csotEnabled() ? Infinity : 2) : 1; + attempt <= maxAttempts; + attempt++, + maxAttempts = previousOperationError?.hasErrorLabel(MongoErrorLabel.SystemOverloadedError) + ? 5 + : maxAttempts + ) { if (previousOperationError) { - if (previousOperationError.hasErrorLabel(MongoErrorLabel.SystemOverloadedError)) { - systemOverloadRetryAttempt += 1; - - // if retryable writes or reads are not configured, throw. - const isOperationConfiguredForRetry = - (hasReadAspect && topology.s.options.retryReads) || - (hasWriteAspect && topology.s.options.retryWrites); - const isRunCommand = operation instanceof RunCommandOperation; - - if ( - // if the SystemOverloadError is not retryable, throw. - !previousOperationError.hasErrorLabel(MongoErrorLabel.RetryableError) || - !(isOperationConfiguredForRetry || isRunCommand) - ) { - throw previousOperationError; - } + if (hasWriteAspect && previousOperationError.code === MMAPv1_RETRY_WRITES_ERROR_CODE) { + throw new MongoServerError({ + message: MMAPv1_RETRY_WRITES_ERROR_MESSAGE, + errmsg: MMAPv1_RETRY_WRITES_ERROR_MESSAGE, + originalError: previousOperationError + }); + } - // if we have exhausted overload retry attempts, throw. - if (systemOverloadRetryAttempt > maxSystemOverloadRetryAttempts) { - throw previousOperationError; - } + const isRetryable = + // bulk write commands are retryable if all operations in the batch are retryable + (operation.hasAspect(Aspect.COMMAND_BATCHING) && operation.canRetryWrite) || + // if we have a retryable read or write operation, we can retry + (hasWriteAspect && isRetryableWriteError(previousOperationError)) || + (hasReadAspect && isRetryableReadError(previousOperationError)) || + // if we have a retryable, system overloaded error, we can retry + (previousOperationError.hasErrorLabel(MongoErrorLabel.SystemOverloadedError) && + previousOperationError.hasErrorLabel(MongoErrorLabel.RetryableError)); + + if (!isRetryable) { + throw previousOperationError; + } - const { value: delayMS } = backoffDelayProvider.next(); + if (previousOperationError.hasErrorLabel(MongoErrorLabel.SystemOverloadedError)) { + const delayMS = backoffDelayProvider.getNextBackoffDuration(); // if the delay would exhaust the CSOT timeout, short-circuit. if (timeoutContext.csotEnabled() && delayMS > timeoutContext.remainingTimeMS) { @@ -298,80 +299,49 @@ async function executeOperationWithRetries< ); } - await setTimeout(delayMS); - if (!topology.tokenBucket.consume(RETRY_COST)) { throw previousOperationError; } - server = await topology.selectServer(selector, { - session, - operationName: operation.commandName, - deprioritizedServers, - signal: operation.options.signal - }); - } else { - nonOverloadRetryAttempt++; - // we have no more retry attempts, throw. - if (nonOverloadRetryAttempt >= maxNonOverloadRetryAttempts) { - throw previousOperationError; - } - - if (hasWriteAspect && previousOperationError.code === MMAPv1_RETRY_WRITES_ERROR_CODE) { - throw new MongoServerError({ - message: MMAPv1_RETRY_WRITES_ERROR_MESSAGE, - errmsg: MMAPv1_RETRY_WRITES_ERROR_MESSAGE, - originalError: previousOperationError - }); - } + await setTimeout(delayMS); + } - if ( - (operation.hasAspect(Aspect.COMMAND_BATCHING) && !operation.canRetryWrite) || - (hasWriteAspect && !isRetryableWriteError(previousOperationError)) || - (hasReadAspect && !isRetryableReadError(previousOperationError)) - ) { - throw previousOperationError; - } + if ( + previousOperationError instanceof MongoNetworkError && + operation.hasAspect(Aspect.CURSOR_CREATING) && + session != null && + session.isPinned && + !session.inTransaction() + ) { + session.unpin({ force: true, forceClear: true }); + } - if ( - previousOperationError instanceof MongoNetworkError && - operation.hasAspect(Aspect.CURSOR_CREATING) && - session != null && - session.isPinned && - !session.inTransaction() - ) { - session.unpin({ force: true, forceClear: true }); - } + server = await topology.selectServer(selector, { + session, + operationName: operation.commandName, + deprioritizedServers, + signal: operation.options.signal + }); - server = await topology.selectServer(selector, { - session, - operationName: operation.commandName, - deprioritizedServers, - signal: operation.options.signal - }); - - if (hasWriteAspect && !supportsRetryableWrites(server)) { - throw new MongoUnexpectedServerResponseError( - 'Selected server does not support retryable writes' - ); - } + if (hasWriteAspect && !supportsRetryableWrites(server)) { + throw new MongoUnexpectedServerResponseError( + 'Selected server does not support retryable writes' + ); } } operation.server = server; try { + const isRetry = attempt > 0; + // If attempt > 0 and we are command batching we need to reset the batch. - if ( - (nonOverloadRetryAttempt > 0 || systemOverloadRetryAttempt > 0) && - operation.hasAspect(Aspect.COMMAND_BATCHING) - ) { + if (isRetry && operation.hasAspect(Aspect.COMMAND_BATCHING)) { operation.resetBatch(); } try { const result = await server.command(operation, timeoutContext); - const isRetry = nonOverloadRetryAttempt > 0 || systemOverloadRetryAttempt > 0; topology.tokenBucket.deposit( isRetry ? // on successful retry, deposit the retry cost + the refresh rate. @@ -404,4 +374,6 @@ async function executeOperationWithRetries< timeoutContext.clear(); } } + + throw previousOperationError ?? new MongoRuntimeError('ahh'); } diff --git a/src/utils.ts b/src/utils.ts index 574c950fbe..6b7b4a0c46 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1432,12 +1432,18 @@ export async function abortable( } } -export function* exponentialBackoffDelayProvider( - maxBackoff: number, - baseBackoff: number, - backoffIncreaseRate: number -): Generator { - for (let i = 0; ; i++) { - yield Math.random() * Math.min(maxBackoff, baseBackoff * backoffIncreaseRate ** i); +export class ExponentialBackoffProvider { + constructor( + public readonly maxBackoff: number, + public readonly baseBackoff: number, + public readonly backoffIncreaseRate: number, + public iteration = 0 + ) {} + + getNextBackoffDuration(): number { + return ( + Math.random() * + Math.min(this.maxBackoff, this.baseBackoff * this.backoffIncreaseRate ** this.iteration) + ); } } From e1f00b7f02d67cade66b7cdb0f61b48726addd6e Mon Sep 17 00:00:00 2001 From: bailey Date: Wed, 17 Dec 2025 12:12:05 -0700 Subject: [PATCH 07/12] update all tests - including new getMore tests --- test/spec/client-backpressure/README.md | 12 +- .../backpressure-retry-loop.json | 3 + .../backpressure-retry-loop.yml | 7 +- .../backpressure-retry-loop.yml.template | 5 +- .../backpressure-retry-max-attempts.json | 3 + .../backpressure-retry-max-attempts.yml | 5 +- ...ckpressure-retry-max-attempts.yml.template | 3 + .../client-backpressure/getMore-retried.json | 161 ++++++++++++++++++ .../client-backpressure/getMore-retried.yml | 81 +++++++++ 9 files changed, 270 insertions(+), 10 deletions(-) create mode 100644 test/spec/client-backpressure/getMore-retried.json create mode 100644 test/spec/client-backpressure/getMore-retried.yml diff --git a/test/spec/client-backpressure/README.md b/test/spec/client-backpressure/README.md index 41ad017c6c..b4b03085e6 100644 --- a/test/spec/client-backpressure/README.md +++ b/test/spec/client-backpressure/README.md @@ -16,8 +16,8 @@ be manually implemented by each driver. Drivers should test that retries do not occur immediately when a SystemOverloadedError is encountered. -1. let `client` be a `MongoClient` -2. let `collection` be a collection +1. Let `client` be a `MongoClient` +2. Let `collection` be a collection 3. Now, run transactions without backoff: 1. Configure the random number generator used for jitter to always return `0` -- this effectively disables backoff. @@ -28,14 +28,14 @@ Drivers should test that retries do not occur immediately when a SystemOverloade configureFailPoint: 'failCommand', mode: 'alwaysOn', data: { - failCommands: ['insert'], - errorCode: 2, - errorLabels: ['SystemOverloadedError', 'RetryableError'] + failCommands: ['insert'], + errorCode: 2, + errorLabels: ['SystemOverloadedError', 'RetryableError'] } } ``` - 3. Execute the following command. Expect that the command errors. Measure the duration of the command execution. + 3. Execute the document `{ a: 1 }`. Expect that the command errors. Measure the duration of the command execution. ```javascript const start = performance.now(); diff --git a/test/spec/client-backpressure/backpressure-retry-loop.json b/test/spec/client-backpressure/backpressure-retry-loop.json index 79cfc4bac7..c4aab441a3 100644 --- a/test/spec/client-backpressure/backpressure-retry-loop.json +++ b/test/spec/client-backpressure/backpressure-retry-loop.json @@ -58,6 +58,9 @@ } } ], + "_yamlAnchors": { + "bulWriteInsertNamespace": "retryable-writes-tests.coll" + }, "tests": [ { "description": "client.listDatabases retries using operation loop", diff --git a/test/spec/client-backpressure/backpressure-retry-loop.yml b/test/spec/client-backpressure/backpressure-retry-loop.yml index a566949453..0112330fcf 100644 --- a/test/spec/client-backpressure/backpressure-retry-loop.yml +++ b/test/spec/client-backpressure/backpressure-retry-loop.yml @@ -37,7 +37,7 @@ createEntities: database: id: &database database client: *client - databaseName: &database_name retryable-writes-tests + databaseName: *database_name - collection: @@ -45,6 +45,9 @@ createEntities: database: *database collectionName: *collection_name +_yamlAnchors: + bulWriteInsertNamespace: &client_bulk_write_ns retryable-writes-tests.coll + tests: - @@ -219,7 +222,7 @@ tests: arguments: models: - insertOne: - namespace: retryable-writes-tests.coll + namespace: *client_bulk_write_ns document: { _id: 8, x: 88 } expectEvents: diff --git a/test/spec/client-backpressure/backpressure-retry-loop.yml.template b/test/spec/client-backpressure/backpressure-retry-loop.yml.template index ac47783e53..f83f462e8a 100644 --- a/test/spec/client-backpressure/backpressure-retry-loop.yml.template +++ b/test/spec/client-backpressure/backpressure-retry-loop.yml.template @@ -37,7 +37,7 @@ createEntities: database: id: &database database client: *client - databaseName: &database_name retryable-writes-tests + databaseName: *database_name - collection: @@ -45,6 +45,9 @@ createEntities: database: *database collectionName: *collection_name +_yamlAnchors: + bulWriteInsertNamespace: &client_bulk_write_ns retryable-writes-tests.coll + tests: {% for operation in operations %} - diff --git a/test/spec/client-backpressure/backpressure-retry-max-attempts.json b/test/spec/client-backpressure/backpressure-retry-max-attempts.json index 0cd52e9a53..1de8cb38d4 100644 --- a/test/spec/client-backpressure/backpressure-retry-max-attempts.json +++ b/test/spec/client-backpressure/backpressure-retry-max-attempts.json @@ -44,6 +44,9 @@ } } ], + "_yamlAnchors": { + "bulkWriteInsertNamespace": "retryable-writes-tests.coll" + }, "initialData": [ { "collectionName": "coll", diff --git a/test/spec/client-backpressure/backpressure-retry-max-attempts.yml b/test/spec/client-backpressure/backpressure-retry-max-attempts.yml index 05da92d671..3800b20a33 100644 --- a/test/spec/client-backpressure/backpressure-retry-max-attempts.yml +++ b/test/spec/client-backpressure/backpressure-retry-max-attempts.yml @@ -32,6 +32,9 @@ createEntities: database: *database collectionName: &collection_name coll +_yamlAnchors: + bulkWriteInsertNamespace: &client_bulk_write_ns retryable-writes-tests.coll + initialData: - collectionName: *collection_name @@ -232,7 +235,7 @@ tests: arguments: models: - insertOne: - namespace: retryable-writes-tests.coll + namespace: *client_bulk_write_ns document: { _id: 8, x: 88 } expectError: isError: true diff --git a/test/spec/client-backpressure/backpressure-retry-max-attempts.yml.template b/test/spec/client-backpressure/backpressure-retry-max-attempts.yml.template index 9efbdfff19..3117d44b89 100644 --- a/test/spec/client-backpressure/backpressure-retry-max-attempts.yml.template +++ b/test/spec/client-backpressure/backpressure-retry-max-attempts.yml.template @@ -32,6 +32,9 @@ createEntities: database: *database collectionName: &collection_name coll +_yamlAnchors: + bulkWriteInsertNamespace: &client_bulk_write_ns retryable-writes-tests.coll + initialData: - collectionName: *collection_name diff --git a/test/spec/client-backpressure/getMore-retried.json b/test/spec/client-backpressure/getMore-retried.json new file mode 100644 index 0000000000..f6d6fecac2 --- /dev/null +++ b/test/spec/client-backpressure/getMore-retried.json @@ -0,0 +1,161 @@ +{ + "description": "getMore-retries-backpressure", + "schemaVersion": "1.3", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent", + "commandFailedEvent", + "commandSucceededEvent" + ] + } + }, + { + "client": { + "id": "failPointClient" + } + }, + { + "database": { + "id": "db", + "client": "client0", + "databaseName": "default" + } + }, + { + "collection": { + "id": "coll", + "database": "db", + "collectionName": "default" + } + } + ], + "initialData": [ + { + "databaseName": "default", + "collectionName": "default", + "documents": [ + { + "a": 1 + }, + { + "a": 2 + }, + { + "a": 3 + } + ] + } + ], + "tests": [ + { + "description": "getMores are retried", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "failPointClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "getMore" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "name": "find", + "arguments": { + "batchSize": 2, + "filter": {}, + "sort": { + "a": 1 + } + }, + "object": "coll", + "expectResult": [ + { + "a": 1 + }, + { + "a": 2 + }, + { + "a": 3 + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandSucceededEvent": { + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "getMore" + } + }, + { + "commandFailedEvent": { + "commandName": "getMore" + } + }, + { + "commandStartedEvent": { + "commandName": "getMore" + } + }, + { + "commandFailedEvent": { + "commandName": "getMore" + } + }, + { + "commandStartedEvent": { + "commandName": "getMore" + } + }, + { + "commandFailedEvent": { + "commandName": "getMore" + } + }, + { + "commandStartedEvent": { + "commandName": "getMore" + } + }, + { + "commandSucceededEvent": { + "commandName": "getMore" + } + } + ] + } + ] + } + ] +} diff --git a/test/spec/client-backpressure/getMore-retried.yml b/test/spec/client-backpressure/getMore-retried.yml new file mode 100644 index 0000000000..9bc925e576 --- /dev/null +++ b/test/spec/client-backpressure/getMore-retried.yml @@ -0,0 +1,81 @@ +description: getMore-retries-backpressure +schemaVersion: "1.3" + +createEntities: + - client: + id: &client client0 + observeEvents: + - commandStartedEvent + - commandFailedEvent + - commandSucceededEvent + - client: + id: &failPointClient failPointClient + - database: + id: db + client: *client + databaseName: &dbName default + - collection: + id: &collection coll + database: db + collectionName: &collectionName default +initialData: + - databaseName: *dbName + collectionName: *collectionName + documents: + - { a: 1 } + - { a: 2 } + - { a: 3 } + +tests: + - description: "getMores are retried" + operations: + - name: failPoint + object: testRunner + arguments: + client: *failPointClient + failPoint: + configureFailPoint: failCommand + mode: { times: 3 } + data: + failCommands: [getMore] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - name: find + arguments: + batchSize: 2 + filter: {} + # ensure stable ordering of result documents + sort: { a: 1 } + object: *collection + expectResult: + - { a: 1 } + - { a: 2 } + - { a: 3 } + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: find + - commandSucceededEvent: + commandName: find + # first attempt + - commandStartedEvent: + commandName: getMore + - commandFailedEvent: + commandName: getMore + # second attempt + - commandStartedEvent: + commandName: getMore + - commandFailedEvent: + commandName: getMore + # third attempt + - commandStartedEvent: + commandName: getMore + - commandFailedEvent: + commandName: getMore + # success + - commandStartedEvent: + commandName: getMore + - commandSucceededEvent: + commandName: getMore \ No newline at end of file From 7cad02c8780928fe175f387bae3ae0099396c693 Mon Sep 17 00:00:00 2001 From: bailey Date: Wed, 17 Dec 2025 12:19:40 -0700 Subject: [PATCH 08/12] getMore tests --- .../client-backpressure/getMore-retried.json | 125 ++++++++++++++++++ .../client-backpressure/getMore-retried.yml | 68 +++++++++- 2 files changed, 192 insertions(+), 1 deletion(-) diff --git a/test/spec/client-backpressure/getMore-retried.json b/test/spec/client-backpressure/getMore-retried.json index f6d6fecac2..f60ad4187d 100644 --- a/test/spec/client-backpressure/getMore-retried.json +++ b/test/spec/client-backpressure/getMore-retried.json @@ -156,6 +156,131 @@ ] } ] + }, + { + "description": "getMores are retried maxAttempts=5 times", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "failPointClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "getMore" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 2 + } + } + } + }, + { + "name": "find", + "arguments": { + "batchSize": 2, + "filter": {} + }, + "object": "coll", + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandSucceededEvent": { + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "getMore" + } + }, + { + "commandFailedEvent": { + "commandName": "getMore" + } + }, + { + "commandStartedEvent": { + "commandName": "getMore" + } + }, + { + "commandFailedEvent": { + "commandName": "getMore" + } + }, + { + "commandStartedEvent": { + "commandName": "getMore" + } + }, + { + "commandFailedEvent": { + "commandName": "getMore" + } + }, + { + "commandStartedEvent": { + "commandName": "getMore" + } + }, + { + "commandFailedEvent": { + "commandName": "getMore" + } + }, + { + "commandStartedEvent": { + "commandName": "getMore" + } + }, + { + "commandFailedEvent": { + "commandName": "getMore" + } + }, + { + "commandStartedEvent": { + "commandName": "getMore" + } + }, + { + "commandFailedEvent": { + "commandName": "getMore" + } + }, + { + "commandStartedEvent": { + "commandName": "killCursors" + } + }, + { + "commandSucceededEvent": { + "commandName": "killCursors" + } + } + ] + } + ] } ] } diff --git a/test/spec/client-backpressure/getMore-retried.yml b/test/spec/client-backpressure/getMore-retried.yml index 9bc925e576..aaef033500 100644 --- a/test/spec/client-backpressure/getMore-retried.yml +++ b/test/spec/client-backpressure/getMore-retried.yml @@ -43,6 +43,7 @@ tests: - name: find arguments: + # batch size of 2 with 3 docs in the collection ensures exactly one find + one getMore exhaust the cursor batchSize: 2 filter: {} # ensure stable ordering of result documents @@ -78,4 +79,69 @@ tests: - commandStartedEvent: commandName: getMore - commandSucceededEvent: - commandName: getMore \ No newline at end of file + commandName: getMore + + - description: "getMores are retried maxAttempts=5 times" + operations: + - name: failPoint + object: testRunner + arguments: + client: *failPointClient + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: [getMore] + errorLabels: [RetryableError, SystemOverloadedError] + errorCode: 2 + + - name: find + arguments: + batchSize: 2 + filter: {} + object: *collection + expectError: + isError: true + isClientError: false + + expectEvents: + - client: *client + events: + - commandStartedEvent: + commandName: find + - commandSucceededEvent: + commandName: find + # first attempt + - commandStartedEvent: + commandName: getMore + - commandFailedEvent: + commandName: getMore + # second attempt + - commandStartedEvent: + commandName: getMore + - commandFailedEvent: + commandName: getMore + # third attempt + - commandStartedEvent: + commandName: getMore + - commandFailedEvent: + commandName: getMore + # fourth attempt + - commandStartedEvent: + commandName: getMore + - commandFailedEvent: + commandName: getMore + # fifth attempt + - commandStartedEvent: + commandName: getMore + - commandFailedEvent: + commandName: getMore + # final attempt + - commandStartedEvent: + commandName: getMore + - commandFailedEvent: + commandName: getMore + - commandStartedEvent: + commandName: killCursors + - commandSucceededEvent: + commandName: killCursors \ No newline at end of file From 253ffa5100e98840f2552cad90f6d4a071ab2fff Mon Sep 17 00:00:00 2001 From: bailey Date: Wed, 17 Dec 2025 12:37:45 -0700 Subject: [PATCH 09/12] committing for diff --- .../unified/backpressure-retryable-abort.json | 357 +++++++++++++++ .../unified/backpressure-retryable-abort.yml | 213 +++++++++ .../backpressure-retryable-commit.json | 377 +++++++++++++++ .../unified/backpressure-retryable-commit.yml | 222 +++++++++ .../unified/backpressure-retryable-reads.json | 346 ++++++++++++++ .../unified/backpressure-retryable-reads.yml | 200 ++++++++ .../backpressure-retryable-writes.json | 433 ++++++++++++++++++ .../unified/backpressure-retryable-writes.yml | 248 ++++++++++ 8 files changed, 2396 insertions(+) create mode 100644 test/spec/transactions/unified/backpressure-retryable-abort.json create mode 100644 test/spec/transactions/unified/backpressure-retryable-abort.yml create mode 100644 test/spec/transactions/unified/backpressure-retryable-commit.json create mode 100644 test/spec/transactions/unified/backpressure-retryable-commit.yml create mode 100644 test/spec/transactions/unified/backpressure-retryable-reads.json create mode 100644 test/spec/transactions/unified/backpressure-retryable-reads.yml create mode 100644 test/spec/transactions/unified/backpressure-retryable-writes.json create mode 100644 test/spec/transactions/unified/backpressure-retryable-writes.yml diff --git a/test/spec/transactions/unified/backpressure-retryable-abort.json b/test/spec/transactions/unified/backpressure-retryable-abort.json new file mode 100644 index 0000000000..df6cf51ffc --- /dev/null +++ b/test/spec/transactions/unified/backpressure-retryable-abort.json @@ -0,0 +1,357 @@ +{ + "description": "retryable-abort-2", + "schemaVersion": "1.3", + "runOnRequirements": [ + { + "minServerVersion": "4.4", + "topologies": [ + "replicaset", + "sharded", + "load-balanced" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": false, + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "transaction-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test" + } + }, + { + "session": { + "id": "session0", + "client": "client0" + } + } + ], + "initialData": [ + { + "collectionName": "test", + "databaseName": "transaction-tests", + "documents": [] + } + ], + "tests": [ + { + "description": "abortTransaction retries if backpressure labels are added", + "operations": [ + { + "object": "testRunner", + "name": "failPoint", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 2 + }, + "data": { + "failCommands": [ + "abortTransaction" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 112 + } + } + } + }, + { + "object": "session0", + "name": "startTransaction" + }, + { + "object": "collection0", + "name": "insertOne", + "arguments": { + "session": "session0", + "document": { + "_id": 1 + } + }, + "expectResult": { + "$$unsetOrMatches": { + "insertedId": { + "$$unsetOrMatches": 1 + } + } + } + }, + { + "object": "session0", + "name": "abortTransaction" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 1 + } + ], + "ordered": true, + "readConcern": { + "$$exists": false + }, + "lsid": { + "$$sessionLsid": "session0" + }, + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": true, + "autocommit": false, + "writeConcern": { + "$$exists": false + } + }, + "commandName": "insert", + "databaseName": "transaction-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "abortTransaction": 1, + "lsid": { + "$$sessionLsid": "session0" + }, + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": { + "$$exists": false + }, + "autocommit": false, + "writeConcern": { + "$$exists": false + } + }, + "commandName": "abortTransaction", + "databaseName": "admin" + } + }, + { + "commandStartedEvent": { + "command": { + "abortTransaction": 1, + "lsid": { + "$$sessionLsid": "session0" + }, + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": { + "$$exists": false + }, + "autocommit": false, + "writeConcern": { + "$$exists": false + } + }, + "commandName": "abortTransaction", + "databaseName": "admin" + } + }, + { + "commandStartedEvent": { + "command": { + "abortTransaction": 1, + "lsid": { + "$$sessionLsid": "session0" + }, + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": { + "$$exists": false + }, + "autocommit": false, + "writeConcern": { + "$$exists": false + } + }, + "commandName": "abortTransaction", + "databaseName": "admin" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test", + "databaseName": "transaction-tests", + "documents": [] + } + ] + }, + { + "description": "abortTransaction is retried maxAttempts=5 times if backpressure labels are added", + "operations": [ + { + "object": "testRunner", + "name": "failPoint", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "abortTransaction" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 112 + } + } + } + }, + { + "object": "session0", + "name": "startTransaction" + }, + { + "object": "collection0", + "name": "insertOne", + "arguments": { + "session": "session0", + "document": { + "_id": 1 + } + }, + "expectResult": { + "$$unsetOrMatches": { + "insertedId": { + "$$unsetOrMatches": 1 + } + } + } + }, + { + "object": "session0", + "name": "abortTransaction" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 1 + } + ], + "ordered": true, + "readConcern": { + "$$exists": false + }, + "lsid": { + "$$sessionLsid": "session0" + }, + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": true, + "autocommit": false, + "writeConcern": { + "$$exists": false + } + }, + "commandName": "insert", + "databaseName": "transaction-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "abortTransaction": 1, + "lsid": { + "$$sessionLsid": "session0" + }, + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": { + "$$exists": false + }, + "autocommit": false, + "writeConcern": { + "$$exists": false + } + }, + "commandName": "abortTransaction", + "databaseName": "admin" + } + }, + { + "commandStartedEvent": { + "commandName": "abortTransaction" + } + }, + { + "commandStartedEvent": { + "commandName": "abortTransaction" + } + }, + { + "commandStartedEvent": { + "commandName": "abortTransaction" + } + }, + { + "commandStartedEvent": { + "commandName": "abortTransaction" + } + }, + { + "commandStartedEvent": { + "commandName": "abortTransaction" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test", + "databaseName": "transaction-tests", + "documents": [] + } + ] + } + ] +} diff --git a/test/spec/transactions/unified/backpressure-retryable-abort.yml b/test/spec/transactions/unified/backpressure-retryable-abort.yml new file mode 100644 index 0000000000..35c6c23a90 --- /dev/null +++ b/test/spec/transactions/unified/backpressure-retryable-abort.yml @@ -0,0 +1,213 @@ +description: retryable-abort +schemaVersion: "1.3" +runOnRequirements: + - minServerVersion: "4.4" + topologies: + - replicaset + - sharded + - load-balanced +createEntities: + - + client: + id: &client0 client0 + useMultipleMongoses: false + observeEvents: + - commandStartedEvent + - + database: + id: &database0 database0 + client: *client0 + databaseName: &database_name transaction-tests + - + collection: + id: &collection0 collection0 + database: *database0 + collectionName: &collection_name test + - + session: + id: &session0 session0 + client: *client0 + +initialData: + - + collectionName: *collection_name + databaseName: *database_name + documents: [] +tests: + - description: abortTransaction retries if backpressure labels are added + operations: + - object: testRunner + name: failPoint + arguments: + client: *client0 + failPoint: + configureFailPoint: failCommand + mode: + times: 2 + data: + failCommands: + - abortTransaction + errorLabels: + - RetryableError + - SystemOverloadedError + errorCode: 112 + - object: *session0 + name: startTransaction + - object: *collection0 + name: insertOne + arguments: + session: *session0 + document: + _id: 1 + expectResult: + $$unsetOrMatches: + insertedId: + $$unsetOrMatches: 1 + - object: *session0 + name: abortTransaction + expectEvents: + - client: *client0 + events: + - commandStartedEvent: + command: + insert: test + documents: + - _id: 1 + ordered: true + readConcern: + $$exists: false + lsid: + $$sessionLsid: *session0 + txnNumber: + $numberLong: "1" + startTransaction: true + autocommit: false + writeConcern: + $$exists: false + commandName: insert + databaseName: *database_name + - commandStartedEvent: + command: + abortTransaction: 1 + lsid: + $$sessionLsid: *session0 + txnNumber: + $numberLong: "1" + startTransaction: + $$exists: false + autocommit: false + writeConcern: + $$exists: false + commandName: abortTransaction + databaseName: admin + - commandStartedEvent: + command: + abortTransaction: 1 + lsid: + $$sessionLsid: *session0 + txnNumber: + $numberLong: "1" + startTransaction: + $$exists: false + autocommit: false + writeConcern: + $$exists: false + commandName: abortTransaction + databaseName: admin + - commandStartedEvent: + command: + abortTransaction: 1 + lsid: + $$sessionLsid: *session0 + txnNumber: + $numberLong: "1" + startTransaction: + $$exists: false + autocommit: false + writeConcern: + $$exists: false + commandName: abortTransaction + databaseName: admin + outcome: + - collectionName: *collection_name + databaseName: *database_name + documents: [] + - description: abortTransaction is retried maxAttempts=5 times if backpressure labels are added + operations: + - object: testRunner + name: failPoint + arguments: + client: *client0 + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: + - abortTransaction + errorLabels: + - RetryableError + - SystemOverloadedError + errorCode: 112 + - object: *session0 + name: startTransaction + - object: *collection0 + name: insertOne + arguments: + session: *session0 + document: + _id: 1 + expectResult: + $$unsetOrMatches: + insertedId: + $$unsetOrMatches: 1 + - object: *session0 + name: abortTransaction + expectEvents: + - client: *client0 + events: + - commandStartedEvent: + command: + insert: test + documents: + - _id: 1 + ordered: true + readConcern: + $$exists: false + lsid: + $$sessionLsid: *session0 + txnNumber: + $numberLong: "1" + startTransaction: true + autocommit: false + writeConcern: + $$exists: false + commandName: insert + databaseName: *database_name + - commandStartedEvent: + command: + abortTransaction: 1 + lsid: + $$sessionLsid: *session0 + txnNumber: + $numberLong: "1" + startTransaction: + $$exists: false + autocommit: false + writeConcern: + $$exists: false + commandName: abortTransaction + databaseName: admin + - commandStartedEvent: + commandName: abortTransaction + - commandStartedEvent: + commandName: abortTransaction + - commandStartedEvent: + commandName: abortTransaction + - commandStartedEvent: + commandName: abortTransaction + - commandStartedEvent: + commandName: abortTransaction + outcome: + - collectionName: *collection_name + databaseName: *database_name + documents: [] diff --git a/test/spec/transactions/unified/backpressure-retryable-commit.json b/test/spec/transactions/unified/backpressure-retryable-commit.json new file mode 100644 index 0000000000..150c0e329f --- /dev/null +++ b/test/spec/transactions/unified/backpressure-retryable-commit.json @@ -0,0 +1,377 @@ +{ + "description": "retryable-commit-2", + "schemaVersion": "1.4", + "runOnRequirements": [ + { + "minServerVersion": "4.4", + "topologies": [ + "sharded", + "replicaset", + "load-balanced" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": false, + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "transaction-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test" + } + }, + { + "session": { + "id": "session0", + "client": "client0" + } + } + ], + "initialData": [ + { + "collectionName": "test", + "databaseName": "transaction-tests", + "documents": [] + } + ], + "tests": [ + { + "description": "commitTransaction retries if backpressure labels are added", + "runOnRequirements": [ + { + "serverless": "forbid" + } + ], + "operations": [ + { + "object": "testRunner", + "name": "failPoint", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 2 + }, + "data": { + "failCommands": [ + "commitTransaction" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 112 + } + } + } + }, + { + "object": "session0", + "name": "startTransaction" + }, + { + "object": "collection0", + "name": "insertOne", + "arguments": { + "session": "session0", + "document": { + "_id": 1 + } + }, + "expectResult": { + "$$unsetOrMatches": { + "insertedId": { + "$$unsetOrMatches": 1 + } + } + } + }, + { + "object": "session0", + "name": "commitTransaction" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 1 + } + ], + "ordered": true, + "readConcern": { + "$$exists": false + }, + "lsid": { + "$$sessionLsid": "session0" + }, + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": true, + "autocommit": false, + "writeConcern": { + "$$exists": false + } + }, + "commandName": "insert", + "databaseName": "transaction-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "commitTransaction": 1, + "lsid": { + "$$sessionLsid": "session0" + }, + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": { + "$$exists": false + }, + "autocommit": false, + "writeConcern": { + "$$exists": false + } + }, + "commandName": "commitTransaction", + "databaseName": "admin" + } + }, + { + "commandStartedEvent": { + "command": { + "commitTransaction": 1, + "lsid": { + "$$sessionLsid": "session0" + }, + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": { + "$$exists": false + }, + "autocommit": false, + "writeConcern": { + "$$exists": false + } + }, + "commandName": "commitTransaction", + "databaseName": "admin" + } + }, + { + "commandStartedEvent": { + "command": { + "commitTransaction": 1, + "lsid": { + "$$sessionLsid": "session0" + }, + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": { + "$$exists": false + }, + "autocommit": false, + "writeConcern": { + "$$exists": false + } + }, + "commandName": "commitTransaction", + "databaseName": "admin" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test", + "databaseName": "transaction-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ] + }, + { + "description": "commitTransaction is retried maxAttempts=5 times if backpressure labels are added", + "runOnRequirements": [ + { + "serverless": "forbid" + } + ], + "operations": [ + { + "object": "testRunner", + "name": "failPoint", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 5 + }, + "data": { + "failCommands": [ + "commitTransaction" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 112 + } + } + } + }, + { + "object": "session0", + "name": "startTransaction" + }, + { + "object": "collection0", + "name": "insertOne", + "arguments": { + "session": "session0", + "document": { + "_id": 1 + } + }, + "expectResult": { + "$$unsetOrMatches": { + "insertedId": { + "$$unsetOrMatches": 1 + } + } + } + }, + { + "object": "session0", + "name": "commitTransaction" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 1 + } + ], + "ordered": true, + "readConcern": { + "$$exists": false + }, + "lsid": { + "$$sessionLsid": "session0" + }, + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": true, + "autocommit": false, + "writeConcern": { + "$$exists": false + } + }, + "commandName": "insert", + "databaseName": "transaction-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "commitTransaction": 1, + "lsid": { + "$$sessionLsid": "session0" + }, + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": { + "$$exists": false + }, + "autocommit": false, + "writeConcern": { + "$$exists": false + } + }, + "commandName": "commitTransaction", + "databaseName": "admin" + } + }, + { + "commandStartedEvent": { + "commandName": "commitTransaction" + } + }, + { + "commandStartedEvent": { + "commandName": "commitTransaction" + } + }, + { + "commandStartedEvent": { + "commandName": "commitTransaction" + } + }, + { + "commandStartedEvent": { + "commandName": "commitTransaction" + } + }, + { + "commandStartedEvent": { + "commandName": "commitTransaction" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test", + "databaseName": "transaction-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ] + } + ] +} diff --git a/test/spec/transactions/unified/backpressure-retryable-commit.yml b/test/spec/transactions/unified/backpressure-retryable-commit.yml new file mode 100644 index 0000000000..99a0a5cb4a --- /dev/null +++ b/test/spec/transactions/unified/backpressure-retryable-commit.yml @@ -0,0 +1,222 @@ +description: retryable-commit +schemaVersion: "1.4" +runOnRequirements: + - minServerVersion: "4.4" + topologies: + - sharded + - replicaset + - load-balanced +createEntities: + - + client: + id: &client0 client0 + useMultipleMongoses: false + observeEvents: + - commandStartedEvent + - + database: + id: &database0 database0 + client: *client0 + databaseName: &database_name transaction-tests + - + collection: + id: &collection0 collection0 + database: *database0 + collectionName: &collection_name test + - + session: + id: &session0 session0 + client: *client0 + +initialData: + - + collectionName: *collection_name + databaseName: *database_name + documents: [] +tests: + - description: commitTransaction retries if backpressure labels are added + runOnRequirements: + - serverless: forbid + operations: + - object: testRunner + name: failPoint + arguments: + client: *client0 + failPoint: + configureFailPoint: failCommand + mode: + times: 2 + data: + failCommands: + - commitTransaction + errorLabels: + - RetryableError + - SystemOverloadedError + errorCode: 112 + - object: *session0 + name: startTransaction + - object: *collection0 + name: insertOne + arguments: + session: *session0 + document: + _id: 1 + expectResult: + $$unsetOrMatches: + insertedId: + $$unsetOrMatches: 1 + - object: *session0 + name: commitTransaction + expectEvents: + - client: *client0 + events: + - commandStartedEvent: + command: + insert: test + documents: + - _id: 1 + ordered: true + readConcern: + $$exists: false + lsid: + $$sessionLsid: *session0 + txnNumber: + $numberLong: "1" + startTransaction: true + autocommit: false + writeConcern: + $$exists: false + commandName: insert + databaseName: *database_name + - commandStartedEvent: + command: + commitTransaction: 1 + lsid: + $$sessionLsid: *session0 + txnNumber: + $numberLong: "1" + startTransaction: + $$exists: false + autocommit: false + writeConcern: + $$exists: false + commandName: commitTransaction + databaseName: admin + - commandStartedEvent: + command: + commitTransaction: 1 + lsid: + $$sessionLsid: *session0 + txnNumber: + $numberLong: "1" + startTransaction: + $$exists: false + autocommit: false + writeConcern: + w: majority + wtimeout: 10000 + commandName: commitTransaction + databaseName: admin + - commandStartedEvent: + command: + commitTransaction: 1 + lsid: + $$sessionLsid: *session0 + txnNumber: + $numberLong: "1" + startTransaction: + $$exists: false + autocommit: false + writeConcern: + w: majority + wtimeout: 10000 + commandName: commitTransaction + databaseName: admin + outcome: + - collectionName: *collection_name + databaseName: *database_name + documents: + - _id: 1 + - description: commitTransaction is retried maxAttempts=5 times if backpressure labels are added + runOnRequirements: + - serverless: forbid + operations: + - object: testRunner + name: failPoint + arguments: + client: *client0 + failPoint: + configureFailPoint: failCommand + mode: + times: 5 + data: + failCommands: + - commitTransaction + errorLabels: + - RetryableError + - SystemOverloadedError + errorCode: 112 + - object: *session0 + name: startTransaction + - object: *collection0 + name: insertOne + arguments: + session: *session0 + document: + _id: 1 + expectResult: + $$unsetOrMatches: + insertedId: + $$unsetOrMatches: 1 + - object: *session0 + name: commitTransaction + expectEvents: + - client: *client0 + events: + - commandStartedEvent: + command: + insert: test + documents: + - _id: 1 + ordered: true + readConcern: + $$exists: false + lsid: + $$sessionLsid: *session0 + txnNumber: + $numberLong: "1" + startTransaction: true + autocommit: false + writeConcern: + $$exists: false + commandName: insert + databaseName: *database_name + - commandStartedEvent: + command: + commitTransaction: 1 + lsid: + $$sessionLsid: *session0 + txnNumber: + $numberLong: "1" + startTransaction: + $$exists: false + autocommit: false + writeConcern: + $$exists: false + commandName: commitTransaction + databaseName: admin + - commandStartedEvent: + commandName: commitTransaction + - commandStartedEvent: + commandName: commitTransaction + - commandStartedEvent: + commandName: commitTransaction + - commandStartedEvent: + commandName: commitTransaction + - commandStartedEvent: + commandName: commitTransaction + outcome: + - collectionName: *collection_name + databaseName: *database_name + documents: + - _id: 1 diff --git a/test/spec/transactions/unified/backpressure-retryable-reads.json b/test/spec/transactions/unified/backpressure-retryable-reads.json new file mode 100644 index 0000000000..ae87cc00c4 --- /dev/null +++ b/test/spec/transactions/unified/backpressure-retryable-reads.json @@ -0,0 +1,346 @@ +{ + "description": "backpressure-retryable-reads", + "schemaVersion": "1.3", + "runOnRequirements": [ + { + "minServerVersion": "4.4", + "topologies": [ + "replicaset", + "sharded", + "load-balanced" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": false, + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "transaction-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test" + } + }, + { + "session": { + "id": "session0", + "client": "client0" + } + } + ], + "initialData": [ + { + "collectionName": "test", + "databaseName": "transaction-tests", + "documents": [] + } + ], + "tests": [ + { + "description": "reads are retried if backpressure labels are added", + "operations": [ + { + "object": "session0", + "name": "startTransaction" + }, + { + "object": "collection0", + "name": "insertOne", + "arguments": { + "session": "session0", + "document": { + "_id": 1 + } + }, + "expectResult": { + "$$unsetOrMatches": { + "insertedId": { + "$$unsetOrMatches": 1 + } + } + } + }, + { + "object": "testRunner", + "name": "failPoint", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "find" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 112 + } + } + } + }, + { + "object": "collection0", + "name": "find", + "arguments": { + "filter": {}, + "session": "session0" + } + }, + { + "object": "session0", + "name": "commitTransaction" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 1 + } + ], + "ordered": true, + "readConcern": { + "$$exists": false + }, + "lsid": { + "$$sessionLsid": "session0" + }, + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": true, + "autocommit": false, + "writeConcern": { + "$$exists": false + } + }, + "commandName": "insert", + "databaseName": "transaction-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "find": "test", + "readConcern": { + "$$exists": false + }, + "lsid": { + "$$sessionLsid": "session0" + }, + "txnNumber": { + "$numberLong": "1" + }, + "autocommit": false, + "writeConcern": { + "$$exists": false + } + }, + "commandName": "find", + "databaseName": "transaction-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "find": "test", + "readConcern": { + "$$exists": false + }, + "lsid": { + "$$sessionLsid": "session0" + }, + "txnNumber": { + "$numberLong": "1" + }, + "autocommit": false, + "writeConcern": { + "$$exists": false + } + }, + "commandName": "find", + "databaseName": "transaction-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "abortTransaction": { + "$$exists": false + }, + "lsid": { + "$$sessionLsid": "session0" + }, + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": { + "$$exists": false + }, + "autocommit": false, + "writeConcern": { + "$$exists": false + } + }, + "commandName": "commitTransaction", + "databaseName": "admin" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test", + "databaseName": "transaction-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ] + }, + { + "description": "reads are retried maxAttempts=5 times if backpressure labels are added", + "operations": [ + { + "object": "session0", + "name": "startTransaction" + }, + { + "object": "collection0", + "name": "insertOne", + "arguments": { + "session": "session0", + "document": { + "_id": 1 + } + }, + "expectResult": { + "$$unsetOrMatches": { + "insertedId": { + "$$unsetOrMatches": 1 + } + } + } + }, + { + "object": "testRunner", + "name": "failPoint", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "find" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 112 + } + } + } + }, + { + "object": "collection0", + "name": "find", + "arguments": { + "filter": {}, + "session": "session0" + }, + "expectError": { + "isError": true + } + }, + { + "object": "session0", + "name": "abortTransaction" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "abortTransaction" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test", + "databaseName": "transaction-tests", + "documents": [] + } + ] + } + ] +} diff --git a/test/spec/transactions/unified/backpressure-retryable-reads.yml b/test/spec/transactions/unified/backpressure-retryable-reads.yml new file mode 100644 index 0000000000..9e3e44d1ed --- /dev/null +++ b/test/spec/transactions/unified/backpressure-retryable-reads.yml @@ -0,0 +1,200 @@ +description: backpressure-retryable-reads +schemaVersion: "1.3" +runOnRequirements: + - minServerVersion: "4.4" + topologies: + - replicaset + - sharded + - load-balanced +createEntities: + - + client: + id: &client0 client0 + useMultipleMongoses: false + observeEvents: + - commandStartedEvent + - + database: + id: &database0 database0 + client: *client0 + databaseName: &database_name transaction-tests + - + collection: + id: &collection0 collection0 + database: *database0 + collectionName: &collection_name test + - + session: + id: &session0 session0 + client: *client0 + +initialData: + - + collectionName: *collection_name + databaseName: *database_name + documents: [] +tests: + - description: reads are retried if backpressure labels are added + operations: + - object: *session0 + name: startTransaction + - object: *collection0 + name: insertOne + arguments: + session: *session0 + document: + _id: 1 + expectResult: + $$unsetOrMatches: + insertedId: + $$unsetOrMatches: 1 + - object: testRunner + name: failPoint + arguments: + client: *client0 + failPoint: + configureFailPoint: failCommand + mode: + times: 1 + data: + failCommands: + - find + errorLabels: + - RetryableError + - SystemOverloadedError + errorCode: 112 + - object: *collection0 + name: find + arguments: + filter: {} + session: *session0 + - object: *session0 + name: commitTransaction + expectEvents: + - client: *client0 + events: + - commandStartedEvent: + command: + insert: test + documents: + - _id: 1 + ordered: true + readConcern: + $$exists: false + lsid: + $$sessionLsid: *session0 + txnNumber: + $numberLong: "1" + startTransaction: true + autocommit: false + writeConcern: + $$exists: false + commandName: insert + databaseName: *database_name + - commandStartedEvent: + command: + find: test + readConcern: + $$exists: false + lsid: + $$sessionLsid: *session0 + txnNumber: + $numberLong: "1" + autocommit: false + writeConcern: + $$exists: false + commandName: find + databaseName: *database_name + - commandStartedEvent: + command: + find: test + readConcern: + $$exists: false + lsid: + $$sessionLsid: *session0 + txnNumber: + $numberLong: "1" + autocommit: false + writeConcern: + $$exists: false + commandName: find + databaseName: *database_name + - commandStartedEvent: + command: + abortTransaction: + $$exists: false + lsid: + $$sessionLsid: *session0 + txnNumber: + $numberLong: "1" + startTransaction: + $$exists: false + autocommit: false + writeConcern: + $$exists: false + commandName: commitTransaction + databaseName: admin + outcome: + - collectionName: *collection_name + databaseName: *database_name + documents: [] + - description: reads are retried maxAttempts=5 times if backpressure labels are added + operations: + - object: *session0 + name: startTransaction + - object: *collection0 + name: insertOne + arguments: + session: *session0 + document: + _id: 1 + expectResult: + $$unsetOrMatches: + insertedId: + $$unsetOrMatches: 1 + - object: testRunner + name: failPoint + arguments: + client: *client0 + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: + - find + errorLabels: + - RetryableError + - SystemOverloadedError + errorCode: 112 + - object: *collection0 + name: find + arguments: + filter: {} + session: *session0 + expectError: + isError: true + - object: *session0 + name: abortTransaction + expectEvents: + - client: *client0 + events: + - commandStartedEvent: + commandName: insert + - commandStartedEvent: + commandName: find + - commandStartedEvent: + commandName: find + - commandStartedEvent: + commandName: find + - commandStartedEvent: + commandName: find + - commandStartedEvent: + commandName: find + - commandStartedEvent: + commandName: find + - commandStartedEvent: + commandName: abortTransaction + outcome: + - collectionName: *collection_name + databaseName: *database_name + documents: [] diff --git a/test/spec/transactions/unified/backpressure-retryable-writes.json b/test/spec/transactions/unified/backpressure-retryable-writes.json new file mode 100644 index 0000000000..628dbd44ea --- /dev/null +++ b/test/spec/transactions/unified/backpressure-retryable-writes.json @@ -0,0 +1,433 @@ +{ + "description": "backpressure-retryable-writes", + "schemaVersion": "1.3", + "runOnRequirements": [ + { + "minServerVersion": "4.4", + "topologies": [ + "replicaset", + "sharded", + "load-balanced" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": false, + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "transaction-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test" + } + }, + { + "session": { + "id": "session0", + "client": "client0" + } + } + ], + "initialData": [ + { + "collectionName": "test", + "databaseName": "transaction-tests", + "documents": [] + } + ], + "tests": [ + { + "description": "writes are retried if backpressure labels are added", + "operations": [ + { + "object": "session0", + "name": "startTransaction" + }, + { + "object": "collection0", + "name": "insertOne", + "arguments": { + "session": "session0", + "document": { + "_id": 1 + } + }, + "expectResult": { + "$$unsetOrMatches": { + "insertedId": { + "$$unsetOrMatches": 1 + } + } + } + }, + { + "object": "testRunner", + "name": "failPoint", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "insert" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 112 + } + } + } + }, + { + "object": "collection0", + "name": "insertOne", + "arguments": { + "session": "session0", + "document": { + "_id": 2 + } + } + }, + { + "object": "session0", + "name": "commitTransaction" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 1 + } + ], + "ordered": true, + "readConcern": { + "$$exists": false + }, + "lsid": { + "$$sessionLsid": "session0" + }, + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": true, + "autocommit": false, + "writeConcern": { + "$$exists": false + } + }, + "commandName": "insert", + "databaseName": "transaction-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 2 + } + ], + "ordered": true, + "readConcern": { + "$$exists": false + }, + "lsid": { + "$$sessionLsid": "session0" + }, + "txnNumber": { + "$numberLong": "1" + }, + "autocommit": false, + "writeConcern": { + "$$exists": false + } + }, + "commandName": "insert", + "databaseName": "transaction-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 2 + } + ], + "ordered": true, + "readConcern": { + "$$exists": false + }, + "lsid": { + "$$sessionLsid": "session0" + }, + "txnNumber": { + "$numberLong": "1" + }, + "autocommit": false, + "writeConcern": { + "$$exists": false + } + }, + "commandName": "insert", + "databaseName": "transaction-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "abortTransaction": { + "$$exists": false + }, + "lsid": { + "$$sessionLsid": "session0" + }, + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": { + "$$exists": false + }, + "autocommit": false, + "writeConcern": { + "$$exists": false + } + }, + "commandName": "commitTransaction", + "databaseName": "admin" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test", + "databaseName": "transaction-tests", + "documents": [] + } + ] + }, + { + "description": "writes are retried maxAttempts=5 times if backpressure labels are added", + "operations": [ + { + "object": "session0", + "name": "startTransaction" + }, + { + "object": "collection0", + "name": "insertOne", + "arguments": { + "session": "session0", + "document": { + "_id": 1 + } + }, + "expectResult": { + "$$unsetOrMatches": { + "insertedId": { + "$$unsetOrMatches": 1 + } + } + } + }, + { + "object": "testRunner", + "name": "failPoint", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": "alwaysOn", + "data": { + "failCommands": [ + "insert" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 112 + } + } + } + }, + { + "object": "collection0", + "name": "insertOne", + "arguments": { + "session": "session0", + "document": { + "_id": 2 + } + }, + "expectError": { + "isError": true + } + }, + { + "object": "session0", + "name": "abortTransaction" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "abortTransaction" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test", + "databaseName": "transaction-tests", + "documents": [] + } + ] + }, + { + "description": "retry succeeds if backpressure labels are added to the first operation in a transaction", + "operations": [ + { + "object": "session0", + "name": "startTransaction" + }, + { + "object": "testRunner", + "name": "failPoint", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "insert" + ], + "errorLabels": [ + "RetryableError", + "SystemOverloadedError" + ], + "errorCode": 112 + } + } + } + }, + { + "object": "collection0", + "name": "insertOne", + "arguments": { + "session": "session0", + "document": { + "_id": 2 + } + } + }, + { + "object": "session0", + "name": "abortTransaction" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "abortTransaction" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test", + "databaseName": "transaction-tests", + "documents": [] + } + ] + } + ] +} diff --git a/test/spec/transactions/unified/backpressure-retryable-writes.yml b/test/spec/transactions/unified/backpressure-retryable-writes.yml new file mode 100644 index 0000000000..5a463f8b48 --- /dev/null +++ b/test/spec/transactions/unified/backpressure-retryable-writes.yml @@ -0,0 +1,248 @@ +description: backpressure-retryable-writes +schemaVersion: "1.3" +runOnRequirements: + - minServerVersion: "4.4" + topologies: + - replicaset + - sharded + - load-balanced +createEntities: + - + client: + id: &client0 client0 + useMultipleMongoses: false + observeEvents: + - commandStartedEvent + - + database: + id: &database0 database0 + client: *client0 + databaseName: &database_name transaction-tests + - + collection: + id: &collection0 collection0 + database: *database0 + collectionName: &collection_name test + - + session: + id: &session0 session0 + client: *client0 + +initialData: + - + collectionName: *collection_name + databaseName: *database_name + documents: [] +tests: + - description: writes are retried if backpressure labels are added + operations: + - object: *session0 + name: startTransaction + - object: *collection0 + name: insertOne + arguments: + session: *session0 + document: + _id: 1 + expectResult: + $$unsetOrMatches: + insertedId: + $$unsetOrMatches: 1 + - object: testRunner + name: failPoint + arguments: + client: *client0 + failPoint: + configureFailPoint: failCommand + mode: + times: 1 + data: + failCommands: + - insert + errorLabels: + - RetryableError + - SystemOverloadedError + errorCode: 112 + - object: *collection0 + name: insertOne + arguments: + session: *session0 + document: + _id: 2 + - object: *session0 + name: commitTransaction + expectEvents: + - client: *client0 + events: + - commandStartedEvent: + command: + insert: test + documents: + - _id: 1 + ordered: true + readConcern: + $$exists: false + lsid: + $$sessionLsid: *session0 + txnNumber: + $numberLong: "1" + startTransaction: true + autocommit: false + writeConcern: + $$exists: false + commandName: insert + databaseName: *database_name + - commandStartedEvent: + command: + insert: test + documents: + - _id: 2 + ordered: true + readConcern: + $$exists: false + lsid: + $$sessionLsid: *session0 + txnNumber: + $numberLong: "1" + autocommit: false + writeConcern: + $$exists: false + commandName: insert + databaseName: *database_name + - commandStartedEvent: + command: + insert: test + documents: + - _id: 2 + ordered: true + readConcern: + $$exists: false + lsid: + $$sessionLsid: *session0 + txnNumber: + $numberLong: "1" + autocommit: false + writeConcern: + $$exists: false + commandName: insert + databaseName: *database_name + - commandStartedEvent: + command: + abortTransaction: + $$exists: false + lsid: + $$sessionLsid: *session0 + txnNumber: + $numberLong: "1" + startTransaction: + $$exists: false + autocommit: false + writeConcern: + $$exists: false + commandName: commitTransaction + databaseName: admin + outcome: + - collectionName: *collection_name + databaseName: *database_name + documents: [] + - description: writes are retried maxAttempts=5 times if backpressure labels are added + operations: + - object: *session0 + name: startTransaction + - object: *collection0 + name: insertOne + arguments: + session: *session0 + document: + _id: 1 + expectResult: + $$unsetOrMatches: + insertedId: + $$unsetOrMatches: 1 + - object: testRunner + name: failPoint + arguments: + client: *client0 + failPoint: + configureFailPoint: failCommand + mode: alwaysOn + data: + failCommands: + - insert + errorLabels: + - RetryableError + - SystemOverloadedError + errorCode: 112 + - object: *collection0 + name: insertOne + arguments: + session: *session0 + document: + _id: 2 + expectError: + isError: true + - object: *session0 + name: abortTransaction + expectEvents: + - client: *client0 + events: + - commandStartedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandStartedEvent: + commandName: abortTransaction + outcome: + - collectionName: *collection_name + databaseName: *database_name + documents: [] + - description: retry succeeds if backpressure labels are added to the first operation in a transaction + operations: + - object: *session0 + name: startTransaction + - object: testRunner + name: failPoint + arguments: + client: *client0 + failPoint: + configureFailPoint: failCommand + mode: + times: 1 + data: + failCommands: + - insert + errorLabels: + - RetryableError + - SystemOverloadedError + errorCode: 112 + - object: *collection0 + name: insertOne + arguments: + session: *session0 + document: + _id: 2 + - object: *session0 + name: abortTransaction + expectEvents: + - client: *client0 + events: + - commandStartedEvent: + commandName: insert + - commandStartedEvent: + commandName: insert + - commandStartedEvent: + commandName: abortTransaction + outcome: + - collectionName: *collection_name + databaseName: *database_name + documents: [] From 39bdcdb761337ccbb9427001e3ac213d968eef9e Mon Sep 17 00:00:00 2001 From: bailey Date: Thu, 18 Dec 2025 14:28:17 -0700 Subject: [PATCH 10/12] WIP --- src/cmap/connection.ts | 3 + src/operations/execute_operation.ts | 19 ++++--- src/operations/operation.ts | 6 ++ src/sessions.ts | 55 +++++++++++++------ sync.sh | 3 +- .../client-backpressure.spec.test.ts | 2 +- .../transactions/transactions.spec.test.ts | 2 +- .../backpressure-retry-loop.json | 4 +- .../backpressure-retry-loop.yml | 2 +- .../backpressure-retry-loop.yml.template | 2 +- .../unified/backpressure-retryable-abort.json | 2 +- .../unified/backpressure-retryable-abort.yml | 2 +- .../backpressure-retryable-commit.json | 17 +++--- .../unified/backpressure-retryable-commit.yml | 16 +++--- .../unified/backpressure-retryable-reads.json | 18 ------ .../unified/backpressure-retryable-reads.yml | 8 --- .../backpressure-retryable-writes.json | 9 ++- .../unified/backpressure-retryable-writes.yml | 4 +- 18 files changed, 95 insertions(+), 79 deletions(-) diff --git a/src/cmap/connection.ts b/src/cmap/connection.ts index 9652e3a5e4..b9ad9729e4 100644 --- a/src/cmap/connection.ts +++ b/src/cmap/connection.ts @@ -582,6 +582,9 @@ export class Connection extends TypedEventEmitter { this.throwIfAborted(); } } catch (error) { + if (options.session != null) { + updateSessionFromResponse(options.session, MongoDBResponse.empty); + } if (this.shouldEmitAndLogCommand) { this.emitAndLogCommand( this.monitorCommands, diff --git a/src/operations/execute_operation.ts b/src/operations/execute_operation.ts index 04cfb7e892..212683b751 100644 --- a/src/operations/execute_operation.ts +++ b/src/operations/execute_operation.ts @@ -37,7 +37,7 @@ import { supportsRetryableWrites } from '../utils'; import { AggregateOperation } from './aggregate'; -import { AbstractOperation, Aspect } from './operation'; +import { AbstractOperation, Aspect, RetryContext } from './operation'; const MMAPv1_RETRY_WRITES_ERROR_CODE = MONGODB_ERROR_CODES.IllegalOperation; const MMAPv1_RETRY_WRITES_ERROR_MESSAGE = @@ -254,13 +254,18 @@ async function executeOperationWithRetries< 2 // backoff rate ); + const retryContext = + operation.retryContext ?? + new RetryContext(willRetry ? (timeoutContext.csotEnabled() ? Infinity : 2) : 1); for ( - let attempt = 0, maxAttempts = willRetry ? (timeoutContext.csotEnabled() ? Infinity : 2) : 1; - attempt <= maxAttempts; + let attempt = 0; + attempt <= retryContext.maxAttempts; attempt++, - maxAttempts = previousOperationError?.hasErrorLabel(MongoErrorLabel.SystemOverloadedError) + retryContext.maxAttempts = previousOperationError?.hasErrorLabel( + MongoErrorLabel.SystemOverloadedError + ) ? 5 - : maxAttempts + : retryContext.maxAttempts ) { if (previousOperationError) { if (hasWriteAspect && previousOperationError.code === MMAPv1_RETRY_WRITES_ERROR_CODE) { @@ -275,8 +280,8 @@ async function executeOperationWithRetries< // bulk write commands are retryable if all operations in the batch are retryable (operation.hasAspect(Aspect.COMMAND_BATCHING) && operation.canRetryWrite) || // if we have a retryable read or write operation, we can retry - (hasWriteAspect && isRetryableWriteError(previousOperationError)) || - (hasReadAspect && isRetryableReadError(previousOperationError)) || + (hasWriteAspect && willRetryWrite && isRetryableWriteError(previousOperationError)) || + (hasReadAspect && willRetryRead && isRetryableReadError(previousOperationError)) || // if we have a retryable, system overloaded error, we can retry (previousOperationError.hasErrorLabel(MongoErrorLabel.SystemOverloadedError) && previousOperationError.hasErrorLabel(MongoErrorLabel.RetryableError)); diff --git a/src/operations/operation.ts b/src/operations/operation.ts index cb0181ee55..8edf6b0509 100644 --- a/src/operations/operation.ts +++ b/src/operations/operation.ts @@ -45,6 +45,10 @@ export interface OperationOptions extends BSONSerializeOptions { timeoutMS?: number; } +export class RetryContext { + constructor(public maxAttempts: number) {} +} + /** * This class acts as a parent class for any operation and is responsible for setting this.options, * as well as setting and getting a session. @@ -66,6 +70,8 @@ export abstract class AbstractOperation { /** Specifies the time an operation will run until it throws a timeout error. */ timeoutMS?: number; + retryContext?: RetryContext; + private _session: ClientSession | undefined; static aspects?: Set; diff --git a/src/sessions.ts b/src/sessions.ts index e282c8617a..9e740b9074 100644 --- a/src/sessions.ts +++ b/src/sessions.ts @@ -23,6 +23,7 @@ import { import type { MongoClient, MongoOptions } from './mongo_client'; import { TypedEventEmitter } from './mongo_types'; import { executeOperation } from './operations/execute_operation'; +import { RetryContext } from './operations/operation'; import { RunCommandOperation } from './operations/run_command'; import { ReadConcernLevel } from './read_concern'; import { ReadPreference } from './read_preference'; @@ -466,7 +467,11 @@ export class ClientSession } else { const wcKeys = Object.keys(wc); if (wcKeys.length > 2 || (!wcKeys.includes('wtimeoutMS') && !wcKeys.includes('wTimeoutMS'))) - // if the write concern was specified with wTimeoutMS, then we set both wtimeoutMS and wTimeoutMS, guaranteeing at least two keys, so if we have more than two keys, then we can automatically assume that we should add the write concern to the command. If it has 2 or fewer keys, we need to check that those keys aren't the wtimeoutMS or wTimeoutMS options before we add the write concern to the command + // if the write concern was specified with wTimeoutMS, then we set both wtimeoutMS + // and wTimeoutMS, guaranteeing at least two keys, so if we have more than two keys, + // then we can automatically assume that we should add the write concern to the command. + // If it has 2 or fewer keys, we need to check that those keys aren't the wtimeoutMS + // or wTimeoutMS options before we add the write concern to the command WriteConcern.apply(command, { ...wc, wtimeoutMS: undefined }); } } @@ -487,11 +492,14 @@ export class ClientSession command.recoveryToken = this.transaction.recoveryToken; } + const retryContext = new RetryContext(5); + const operation = new RunCommandOperation(new MongoDBNamespace('admin'), command, { session: this, readPreference: ReadPreference.primary, bypassPinningCheck: true }); + operation.retryContext = retryContext; const timeoutContext = this.timeoutContext ?? @@ -516,15 +524,13 @@ export class ClientSession this.unpin({ force: true }); try { - await executeOperation( - this.client, - new RunCommandOperation(new MongoDBNamespace('admin'), command, { - session: this, - readPreference: ReadPreference.primary, - bypassPinningCheck: true - }), - timeoutContext - ); + const op = new RunCommandOperation(new MongoDBNamespace('admin'), command, { + session: this, + readPreference: ReadPreference.primary, + bypassPinningCheck: true + }); + op.retryContext = retryContext; + await executeOperation(this.client, op, timeoutContext); return; } catch (retryCommitError) { // If the retry failed, we process that error instead of the original @@ -957,6 +963,11 @@ export class ServerSession { id: ServerSessionId; lastUse: number; txnNumber: number; + + /* + * Indicates that a network error has been encountered while using this session. + * Once a session is marked as dirty, it is always dirty. + */ isDirty: boolean; /** @internal */ @@ -1050,16 +1061,15 @@ export class ServerSessionPool { * @param session - The session to release to the pool */ release(session: ServerSession): void { - const sessionTimeoutMinutes = this.client.topology?.logicalSessionTimeoutMinutes ?? 10; + if (this.client.topology?.loadBalanced) { + if (session.isDirty) return; - if (this.client.topology?.loadBalanced && !sessionTimeoutMinutes) { this.sessions.unshift(session); - } - - if (!sessionTimeoutMinutes) { return; } + const sessionTimeoutMinutes = this.client.topology?.logicalSessionTimeoutMinutes ?? 10; + this.sessions.prune(session => session.hasTimedOut(sessionTimeoutMinutes)); if (!session.hasTimedOut(sessionTimeoutMinutes)) { @@ -1147,9 +1157,9 @@ export function applySession( command.autocommit = false; if (session.transaction.state === TxnState.STARTING_TRANSACTION) { - session.transaction.transition(TxnState.TRANSACTION_IN_PROGRESS); command.startTransaction = true; + // TODO: read concern only applied if it is not the same as the server's default const readConcern = session.transaction.options.readConcern || session?.clientOptions?.readConcern; if (readConcern) { @@ -1185,4 +1195,17 @@ export function updateSessionFromResponse(session: ClientSession, document: Mong session.snapshotTime = atClusterTime; } } + + if (session.transaction.state === TxnState.STARTING_TRANSACTION) { + if (document.ok === 1) { + session.transaction.transition(TxnState.TRANSACTION_IN_PROGRESS); + } else { + const error = new MongoServerError(document.toObject()); + const isBackpressureError = error.hasErrorLabel(MongoErrorLabel.RetryableError); + + if (!isBackpressureError) { + session.transaction.transition(TxnState.TRANSACTION_IN_PROGRESS); + } + } + } } diff --git a/sync.sh b/sync.sh index aab954ba4e..b99d9ed108 100644 --- a/sync.sh +++ b/sync.sh @@ -1,3 +1,4 @@ -cp ~/dev/specifications/source/client-backpressure/tests/* ~/dev/node-mongodb-native/test/spec/client-backpressure \ No newline at end of file +cp ~/dev/specifications/source/client-backpressure/tests/* ~/dev/node-mongodb-native/test/spec/client-backpressure +cp ~/dev/specifications/source/transactions/tests/unified/backpressure* ~/dev/node-mongodb-native/test/spec/transactions/unified/ \ No newline at end of file diff --git a/test/integration/client-backpressure/client-backpressure.spec.test.ts b/test/integration/client-backpressure/client-backpressure.spec.test.ts index 9485c46a96..604f75aa87 100644 --- a/test/integration/client-backpressure/client-backpressure.spec.test.ts +++ b/test/integration/client-backpressure/client-backpressure.spec.test.ts @@ -11,6 +11,6 @@ function shouldSkip({ description }: Test) { return skippedTests[description] ?? false; } -describe('Client Backpressure (spec)', function () { +describe.only('Client Backpressure (spec)', function () { runUnifiedSuite(loadSpecTests('client-backpressure'), shouldSkip); }); diff --git a/test/integration/transactions/transactions.spec.test.ts b/test/integration/transactions/transactions.spec.test.ts index ab6f84b1e9..b24f1a667c 100644 --- a/test/integration/transactions/transactions.spec.test.ts +++ b/test/integration/transactions/transactions.spec.test.ts @@ -13,7 +13,7 @@ const SKIPPED_TESTS = [ 'client bulkWrite with writeConcern in a transaction causes a transaction error' ]; -describe('Transactions Spec Unified Tests', function () { +describe.only('Transactions Spec Unified Tests', function () { runUnifiedSuite(loadSpecTests(path.join('transactions', 'unified')), test => { return SKIPPED_TESTS.includes(test.description) ? 'TODO(NODE-5924): Skipping failing transaction tests' diff --git a/test/spec/client-backpressure/backpressure-retry-loop.json b/test/spec/client-backpressure/backpressure-retry-loop.json index c4aab441a3..f9253774b3 100644 --- a/test/spec/client-backpressure/backpressure-retry-loop.json +++ b/test/spec/client-backpressure/backpressure-retry-loop.json @@ -31,7 +31,7 @@ }, { "database": { - "id": "database", + "id": "internal_db", "client": "internal_client", "databaseName": "retryable-writes-tests" } @@ -39,7 +39,7 @@ { "collection": { "id": "retryable-writes-tests", - "database": "database", + "database": "internal_db", "collectionName": "coll" } }, diff --git a/test/spec/client-backpressure/backpressure-retry-loop.yml b/test/spec/client-backpressure/backpressure-retry-loop.yml index 0112330fcf..8e1aa7f00e 100644 --- a/test/spec/client-backpressure/backpressure-retry-loop.yml +++ b/test/spec/client-backpressure/backpressure-retry-loop.yml @@ -23,7 +23,7 @@ createEntities: - database: - id: &internal_db database + id: &internal_db internal_db client: *internal_client databaseName: &database_name retryable-writes-tests diff --git a/test/spec/client-backpressure/backpressure-retry-loop.yml.template b/test/spec/client-backpressure/backpressure-retry-loop.yml.template index f83f462e8a..44e0bdf99a 100644 --- a/test/spec/client-backpressure/backpressure-retry-loop.yml.template +++ b/test/spec/client-backpressure/backpressure-retry-loop.yml.template @@ -23,7 +23,7 @@ createEntities: - database: - id: &internal_db database + id: &internal_db internal_db client: *internal_client databaseName: &database_name retryable-writes-tests diff --git a/test/spec/transactions/unified/backpressure-retryable-abort.json b/test/spec/transactions/unified/backpressure-retryable-abort.json index df6cf51ffc..53fc9c6f09 100644 --- a/test/spec/transactions/unified/backpressure-retryable-abort.json +++ b/test/spec/transactions/unified/backpressure-retryable-abort.json @@ -1,5 +1,5 @@ { - "description": "retryable-abort-2", + "description": "backpressure-retryable-abort", "schemaVersion": "1.3", "runOnRequirements": [ { diff --git a/test/spec/transactions/unified/backpressure-retryable-abort.yml b/test/spec/transactions/unified/backpressure-retryable-abort.yml index 35c6c23a90..85532e1f60 100644 --- a/test/spec/transactions/unified/backpressure-retryable-abort.yml +++ b/test/spec/transactions/unified/backpressure-retryable-abort.yml @@ -1,4 +1,4 @@ -description: retryable-abort +description: backpressure-retryable-abort schemaVersion: "1.3" runOnRequirements: - minServerVersion: "4.4" diff --git a/test/spec/transactions/unified/backpressure-retryable-commit.json b/test/spec/transactions/unified/backpressure-retryable-commit.json index 150c0e329f..ae873561a9 100644 --- a/test/spec/transactions/unified/backpressure-retryable-commit.json +++ b/test/spec/transactions/unified/backpressure-retryable-commit.json @@ -1,5 +1,5 @@ { - "description": "retryable-commit-2", + "description": "backpressure-retryable-commit", "schemaVersion": "1.4", "runOnRequirements": [ { @@ -236,9 +236,7 @@ "client": "client0", "failPoint": { "configureFailPoint": "failCommand", - "mode": { - "times": 5 - }, + "mode": "alwaysOn", "data": { "failCommands": [ "commitTransaction" @@ -275,7 +273,10 @@ }, { "object": "session0", - "name": "commitTransaction" + "name": "commitTransaction", + "expectError": { + "isError": true + } } ], "expectEvents": [ @@ -365,11 +366,7 @@ { "collectionName": "test", "databaseName": "transaction-tests", - "documents": [ - { - "_id": 1 - } - ] + "documents": [] } ] } diff --git a/test/spec/transactions/unified/backpressure-retryable-commit.yml b/test/spec/transactions/unified/backpressure-retryable-commit.yml index 99a0a5cb4a..8099e1c1eb 100644 --- a/test/spec/transactions/unified/backpressure-retryable-commit.yml +++ b/test/spec/transactions/unified/backpressure-retryable-commit.yml @@ -1,4 +1,4 @@ -description: retryable-commit +description: backpressure-retryable-commit schemaVersion: "1.4" runOnRequirements: - minServerVersion: "4.4" @@ -113,8 +113,7 @@ tests: $$exists: false autocommit: false writeConcern: - w: majority - wtimeout: 10000 + $$exists: false commandName: commitTransaction databaseName: admin - commandStartedEvent: @@ -128,8 +127,7 @@ tests: $$exists: false autocommit: false writeConcern: - w: majority - wtimeout: 10000 + $$exists: false commandName: commitTransaction databaseName: admin outcome: @@ -147,8 +145,7 @@ tests: client: *client0 failPoint: configureFailPoint: failCommand - mode: - times: 5 + mode: alwaysOn data: failCommands: - commitTransaction @@ -170,6 +167,8 @@ tests: $$unsetOrMatches: 1 - object: *session0 name: commitTransaction + expectError: + isError: true expectEvents: - client: *client0 events: @@ -218,5 +217,4 @@ tests: outcome: - collectionName: *collection_name databaseName: *database_name - documents: - - _id: 1 + documents: [] diff --git a/test/spec/transactions/unified/backpressure-retryable-reads.json b/test/spec/transactions/unified/backpressure-retryable-reads.json index ae87cc00c4..731762830e 100644 --- a/test/spec/transactions/unified/backpressure-retryable-reads.json +++ b/test/spec/transactions/unified/backpressure-retryable-reads.json @@ -213,17 +213,6 @@ } ] } - ], - "outcome": [ - { - "collectionName": "test", - "databaseName": "transaction-tests", - "documents": [ - { - "_id": 1 - } - ] - } ] }, { @@ -333,13 +322,6 @@ } ] } - ], - "outcome": [ - { - "collectionName": "test", - "databaseName": "transaction-tests", - "documents": [] - } ] } ] diff --git a/test/spec/transactions/unified/backpressure-retryable-reads.yml b/test/spec/transactions/unified/backpressure-retryable-reads.yml index 9e3e44d1ed..18bbdaadbf 100644 --- a/test/spec/transactions/unified/backpressure-retryable-reads.yml +++ b/test/spec/transactions/unified/backpressure-retryable-reads.yml @@ -134,10 +134,6 @@ tests: $$exists: false commandName: commitTransaction databaseName: admin - outcome: - - collectionName: *collection_name - databaseName: *database_name - documents: [] - description: reads are retried maxAttempts=5 times if backpressure labels are added operations: - object: *session0 @@ -194,7 +190,3 @@ tests: commandName: find - commandStartedEvent: commandName: abortTransaction - outcome: - - collectionName: *collection_name - databaseName: *database_name - documents: [] diff --git a/test/spec/transactions/unified/backpressure-retryable-writes.json b/test/spec/transactions/unified/backpressure-retryable-writes.json index 628dbd44ea..0817e03f2f 100644 --- a/test/spec/transactions/unified/backpressure-retryable-writes.json +++ b/test/spec/transactions/unified/backpressure-retryable-writes.json @@ -232,7 +232,14 @@ { "collectionName": "test", "databaseName": "transaction-tests", - "documents": [] + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] } ] }, diff --git a/test/spec/transactions/unified/backpressure-retryable-writes.yml b/test/spec/transactions/unified/backpressure-retryable-writes.yml index 5a463f8b48..630c9d9694 100644 --- a/test/spec/transactions/unified/backpressure-retryable-writes.yml +++ b/test/spec/transactions/unified/backpressure-retryable-writes.yml @@ -144,7 +144,9 @@ tests: outcome: - collectionName: *collection_name databaseName: *database_name - documents: [] + documents: + - { _id: 1 } + - { _id: 2 } - description: writes are retried maxAttempts=5 times if backpressure labels are added operations: - object: *session0 From 611a17c37af23f2fa7922c6c6df7d1f139085fa8 Mon Sep 17 00:00:00 2001 From: bailey Date: Thu, 18 Dec 2025 14:52:25 -0700 Subject: [PATCH 11/12] passing tests --- src/cmap/connection.ts | 2 +- src/operations/execute_operation.ts | 4 ++-- .../client-backpressure/client-backpressure.spec.test.ts | 2 +- test/integration/transactions/transactions.spec.test.ts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cmap/connection.ts b/src/cmap/connection.ts index b9ad9729e4..2a3e5a3b9a 100644 --- a/src/cmap/connection.ts +++ b/src/cmap/connection.ts @@ -582,7 +582,7 @@ export class Connection extends TypedEventEmitter { this.throwIfAborted(); } } catch (error) { - if (options.session != null) { + if (options.session != null && !(error instanceof MongoServerError)) { updateSessionFromResponse(options.session, MongoDBResponse.empty); } if (this.shouldEmitAndLogCommand) { diff --git a/src/operations/execute_operation.ts b/src/operations/execute_operation.ts index 212683b751..1643064dc7 100644 --- a/src/operations/execute_operation.ts +++ b/src/operations/execute_operation.ts @@ -259,12 +259,12 @@ async function executeOperationWithRetries< new RetryContext(willRetry ? (timeoutContext.csotEnabled() ? Infinity : 2) : 1); for ( let attempt = 0; - attempt <= retryContext.maxAttempts; + attempt < retryContext.maxAttempts; attempt++, retryContext.maxAttempts = previousOperationError?.hasErrorLabel( MongoErrorLabel.SystemOverloadedError ) - ? 5 + ? 6 : retryContext.maxAttempts ) { if (previousOperationError) { diff --git a/test/integration/client-backpressure/client-backpressure.spec.test.ts b/test/integration/client-backpressure/client-backpressure.spec.test.ts index 604f75aa87..9485c46a96 100644 --- a/test/integration/client-backpressure/client-backpressure.spec.test.ts +++ b/test/integration/client-backpressure/client-backpressure.spec.test.ts @@ -11,6 +11,6 @@ function shouldSkip({ description }: Test) { return skippedTests[description] ?? false; } -describe.only('Client Backpressure (spec)', function () { +describe('Client Backpressure (spec)', function () { runUnifiedSuite(loadSpecTests('client-backpressure'), shouldSkip); }); diff --git a/test/integration/transactions/transactions.spec.test.ts b/test/integration/transactions/transactions.spec.test.ts index b24f1a667c..ab6f84b1e9 100644 --- a/test/integration/transactions/transactions.spec.test.ts +++ b/test/integration/transactions/transactions.spec.test.ts @@ -13,7 +13,7 @@ const SKIPPED_TESTS = [ 'client bulkWrite with writeConcern in a transaction causes a transaction error' ]; -describe.only('Transactions Spec Unified Tests', function () { +describe('Transactions Spec Unified Tests', function () { runUnifiedSuite(loadSpecTests(path.join('transactions', 'unified')), test => { return SKIPPED_TESTS.includes(test.description) ? 'TODO(NODE-5924): Skipping failing transaction tests' From e72961b3161e289830cadd79bf9e644f7101c21f Mon Sep 17 00:00:00 2001 From: bailey Date: Thu, 18 Dec 2025 15:56:20 -0700 Subject: [PATCH 12/12] last changes --- src/operations/execute_operation.ts | 9 +- test/spec/client-backpressure/README.md | 6 +- .../backpressure-retry-loop.json | 231 +----------------- .../backpressure-retry-loop.yml | 227 +++-------------- .../backpressure-retry-loop.yml.template | 11 +- test/unit/index.test.ts | 1 + 6 files changed, 54 insertions(+), 431 deletions(-) diff --git a/src/operations/execute_operation.ts b/src/operations/execute_operation.ts index 1643064dc7..f68ce5b1d9 100644 --- a/src/operations/execute_operation.ts +++ b/src/operations/execute_operation.ts @@ -261,11 +261,10 @@ async function executeOperationWithRetries< let attempt = 0; attempt < retryContext.maxAttempts; attempt++, - retryContext.maxAttempts = previousOperationError?.hasErrorLabel( - MongoErrorLabel.SystemOverloadedError - ) - ? 6 - : retryContext.maxAttempts + retryContext.maxAttempts = + willRetry && previousOperationError?.hasErrorLabel(MongoErrorLabel.SystemOverloadedError) + ? 6 + : retryContext.maxAttempts ) { if (previousOperationError) { if (hasWriteAspect && previousOperationError.code === MMAPv1_RETRY_WRITES_ERROR_CODE) { diff --git a/test/spec/client-backpressure/README.md b/test/spec/client-backpressure/README.md index b4b03085e6..9f49b1ed20 100644 --- a/test/spec/client-backpressure/README.md +++ b/test/spec/client-backpressure/README.md @@ -35,7 +35,7 @@ Drivers should test that retries do not occur immediately when a SystemOverloade } ``` - 3. Execute the document `{ a: 1 }`. Expect that the command errors. Measure the duration of the command execution. + 3. Insert the document `{ a: 1 }`. Expect that the command errors. Measure the duration of the command execution. ```javascript const start = performance.now(); @@ -55,7 +55,3 @@ Drivers should test that retries do not occur immediately when a SystemOverloade ``` The sum of 5 backoffs is 3.1 seconds. There is a 1-second window to account for potential variance between the two runs. - -## Changelog - -- 2025-XX-XX: Initial version. diff --git a/test/spec/client-backpressure/backpressure-retry-loop.json b/test/spec/client-backpressure/backpressure-retry-loop.json index f9253774b3..2542344b38 100644 --- a/test/spec/client-backpressure/backpressure-retry-loop.json +++ b/test/spec/client-backpressure/backpressure-retry-loop.json @@ -58,6 +58,13 @@ } } ], + "initialData": [ + { + "collectionName": "coll", + "databaseName": "retryable-writes-tests", + "documents": [] + } + ], "_yamlAnchors": { "bulWriteInsertNamespace": "retryable-writes-tests.coll" }, @@ -65,13 +72,6 @@ { "description": "client.listDatabases retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -154,13 +154,6 @@ { "description": "client.listDatabaseNames retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -240,13 +233,6 @@ { "description": "client.createChangeStream retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -334,13 +320,6 @@ } ], "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -433,13 +412,6 @@ { "description": "database.aggregate retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -529,13 +501,6 @@ { "description": "database.listCollections retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -618,13 +583,6 @@ { "description": "database.listCollectionNames retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -707,13 +665,6 @@ { "description": "database.runCommand retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -799,13 +750,6 @@ { "description": "database.createChangeStream retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -888,13 +832,6 @@ { "description": "collection.aggregate retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -977,13 +914,6 @@ { "description": "collection.countDocuments retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -1066,13 +996,6 @@ { "description": "collection.estimatedDocumentCount retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -1152,13 +1075,6 @@ { "description": "collection.distinct retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -1242,13 +1158,6 @@ { "description": "collection.find retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -1331,13 +1240,6 @@ { "description": "collection.findOne retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -1420,13 +1322,6 @@ { "description": "collection.listIndexes retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -1506,13 +1401,6 @@ { "description": "collection.listIndexNames retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -1592,13 +1480,6 @@ { "description": "collection.createChangeStream retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -1681,13 +1562,6 @@ { "description": "collection.insertOne retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -1773,13 +1647,6 @@ { "description": "collection.insertMany retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -1867,13 +1734,6 @@ { "description": "collection.deleteOne retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -1956,13 +1816,6 @@ { "description": "collection.deleteMany retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -2045,13 +1898,6 @@ { "description": "collection.replaceOne retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -2137,13 +1983,6 @@ { "description": "collection.updateOne retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -2231,13 +2070,6 @@ { "description": "collection.updateMany retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -2325,13 +2157,6 @@ { "description": "collection.findOneAndDelete retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -2414,13 +2239,6 @@ { "description": "collection.findOneAndReplace retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -2506,13 +2324,6 @@ { "description": "collection.findOneAndUpdate retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -2600,13 +2411,6 @@ { "description": "collection.bulkWrite retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -2698,13 +2502,6 @@ { "description": "collection.createIndex retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", @@ -2790,13 +2587,6 @@ { "description": "collection.dropIndex retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "object": "retryable-writes-tests", "name": "createIndex", @@ -2889,13 +2679,6 @@ { "description": "collection.dropIndexes retries using operation loop", "operations": [ - { - "object": "retryable-writes-tests", - "name": "deleteMany", - "arguments": { - "filter": {} - } - }, { "name": "failPoint", "object": "testRunner", diff --git a/test/spec/client-backpressure/backpressure-retry-loop.yml b/test/spec/client-backpressure/backpressure-retry-loop.yml index 8e1aa7f00e..6a3033989b 100644 --- a/test/spec/client-backpressure/backpressure-retry-loop.yml +++ b/test/spec/client-backpressure/backpressure-retry-loop.yml @@ -45,6 +45,11 @@ createEntities: database: *database collectionName: *collection_name +initialData: +- collectionName: *collection_name + databaseName: *database_name + documents: [] + _yamlAnchors: bulWriteInsertNamespace: &client_bulk_write_ns retryable-writes-tests.coll @@ -52,12 +57,7 @@ tests: - description: 'client.listDatabases retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -100,12 +100,7 @@ tests: - description: 'client.listDatabaseNames retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -146,12 +141,7 @@ tests: - description: 'client.createChangeStream retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -196,12 +186,7 @@ tests: description: 'client.clientBulkWrite retries using operation loop' runOnRequirements: - minServerVersion: '8.0' # client bulk write added to server in 8.0 - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -247,12 +232,7 @@ tests: - description: 'database.aggregate retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -295,12 +275,7 @@ tests: - description: 'database.listCollections retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -343,12 +318,7 @@ tests: - description: 'database.listCollectionNames retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -391,12 +361,7 @@ tests: - description: 'database.runCommand retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -440,12 +405,7 @@ tests: - description: 'database.createChangeStream retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -488,12 +448,7 @@ tests: - description: 'collection.aggregate retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -536,12 +491,7 @@ tests: - description: 'collection.countDocuments retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -584,12 +534,7 @@ tests: - description: 'collection.estimatedDocumentCount retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -630,12 +575,7 @@ tests: - description: 'collection.distinct retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -679,12 +619,7 @@ tests: - description: 'collection.find retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -727,12 +662,7 @@ tests: - description: 'collection.findOne retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -775,12 +705,7 @@ tests: - description: 'collection.listIndexes retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -821,12 +746,7 @@ tests: - description: 'collection.listIndexNames retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -867,12 +787,7 @@ tests: - description: 'collection.createChangeStream retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -915,12 +830,7 @@ tests: - description: 'collection.insertOne retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -963,12 +873,7 @@ tests: - description: 'collection.insertMany retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -1012,12 +917,7 @@ tests: - description: 'collection.deleteOne retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -1060,12 +960,7 @@ tests: - description: 'collection.deleteMany retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -1108,12 +1003,7 @@ tests: - description: 'collection.replaceOne retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -1157,12 +1047,7 @@ tests: - description: 'collection.updateOne retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -1206,12 +1091,7 @@ tests: - description: 'collection.updateMany retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -1255,12 +1135,7 @@ tests: - description: 'collection.findOneAndDelete retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -1303,12 +1178,7 @@ tests: - description: 'collection.findOneAndReplace retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -1352,12 +1222,7 @@ tests: - description: 'collection.findOneAndUpdate retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -1401,12 +1266,7 @@ tests: - description: 'collection.bulkWrite retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -1451,12 +1311,7 @@ tests: - description: 'collection.createIndex retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint @@ -1501,11 +1356,6 @@ tests: - description: 'collection.dropIndex retries using operation loop' operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} - object: *internal_collection name: createIndex @@ -1554,12 +1404,7 @@ tests: - description: 'collection.dropIndexes retries using operation loop' - operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} + operations: - name: failPoint diff --git a/test/spec/client-backpressure/backpressure-retry-loop.yml.template b/test/spec/client-backpressure/backpressure-retry-loop.yml.template index 44e0bdf99a..df1afe95cf 100644 --- a/test/spec/client-backpressure/backpressure-retry-loop.yml.template +++ b/test/spec/client-backpressure/backpressure-retry-loop.yml.template @@ -45,6 +45,11 @@ createEntities: database: *database collectionName: *collection_name +initialData: +- collectionName: *collection_name + databaseName: *database_name + documents: [] + _yamlAnchors: bulWriteInsertNamespace: &client_bulk_write_ns retryable-writes-tests.coll @@ -57,12 +62,6 @@ tests: - minServerVersion: '8.0' # client bulk write added to server in 8.0 {%- endif %} operations: - - - object: *internal_collection - name: deleteMany - arguments: - filter: {} - {%- if operation.operation_name == "dropIndex" %} - object: *internal_collection diff --git a/test/unit/index.test.ts b/test/unit/index.test.ts index 7b73c22b82..9e74808e29 100644 --- a/test/unit/index.test.ts +++ b/test/unit/index.test.ts @@ -132,6 +132,7 @@ const EXPECTED_EXPORTS = [ 'SeverityLevel', 'SrvPollingEvent', 'Timestamp', + 'TokenBucket', 'TopologyClosedEvent', 'TopologyDescriptionChangedEvent', 'TopologyOpeningEvent',