diff --git a/.evergreen/.evg.yml b/.evergreen/.evg.yml index 1cc9508af3f..56960d41a76 100644 --- a/.evergreen/.evg.yml +++ b/.evergreen/.evg.yml @@ -1740,6 +1740,10 @@ axes: display_name: "8.0" variables: VERSION: "8.0" + - id: "9.0" + display_name: "9.0" + variables: + VERSION: "9.0" # 8.2 is used solely for Windows testing. MongoDB 8.0 binaries are affected by SERVER-116018 on Windows, # and the fix is only available starting from 8.2. - id: "8.2" @@ -2341,7 +2345,7 @@ buildvariants: # - matrix_name: "tests-zlib-compression" - matrix_spec: { compressor: "zlib", auth: "noauth", ssl: "nossl", jdk: "jdk8", version: [ "4.2", "4.4", "5.0", "6.0", "7.0", "8.0", "latest" ], topology: "standalone", os: "linux" } + matrix_spec: { compressor: "zlib", auth: "noauth", ssl: "nossl", jdk: "jdk8", version: [ "4.2", "4.4", "5.0", "6.0", "7.0", "8.0", "9.0", "latest" ], topology: "standalone", os: "linux" } display_name: "${version} ${compressor} ${topology} ${auth} ${ssl} ${jdk} ${os} " tags: [ "tests-variant" ] tasks: @@ -2351,7 +2355,7 @@ buildvariants: - name: "test-legacy-task" - matrix_name: "tests-snappy-compression" - matrix_spec: { compressor: "snappy", auth: "noauth", ssl: "nossl", jdk: "jdk8", version: [ "4.2", "4.4", "5.0", "6.0", "7.0", "8.0", "latest" ], topology: "standalone", os: "linux" } + matrix_spec: { compressor: "snappy", auth: "noauth", ssl: "nossl", jdk: "jdk8", version: [ "4.2", "4.4", "5.0", "6.0", "7.0", "8.0", "9.0", "latest" ], topology: "standalone", os: "linux" } display_name: "${version} ${compressor} ${topology} ${auth} ${ssl} ${jdk} ${os} " tags: [ "tests-variant" ] tasks: @@ -2362,7 +2366,7 @@ buildvariants: - matrix_name: "tests-zstd-compression" matrix_spec: { compressor: "zstd", auth: "noauth", ssl: "nossl", jdk: "jdk8", - version: [ "4.2", "4.4", "5.0", "6.0", "7.0", "8.0", "latest" ], + version: [ "4.2", "4.4", "5.0", "6.0", "7.0", "8.0", "9.0", "latest" ], topology: "standalone", os: "linux" } display_name: "${version} ${compressor} ${topology} ${auth} ${ssl} ${jdk} ${os} " tags: [ "tests-variant" ] @@ -2380,7 +2384,7 @@ buildvariants: - name: "test-bson-and-crypt-task" - matrix_name: "tests-jdk8-unsecure" - matrix_spec: { auth: "noauth", ssl: "nossl", jdk: "jdk8", version: [ "4.2", "4.4", "5.0", "6.0", "7.0", "8.0", "latest" ], + matrix_spec: { auth: "noauth", ssl: "nossl", jdk: "jdk8", version: [ "4.2", "4.4", "5.0", "6.0", "7.0", "8.0", "9.0", "latest" ], topology: "*", os: "linux" } display_name: "${version} ${topology} ${auth} ${ssl} ${jdk} ${os} " tags: [ "tests-variant" ] @@ -2392,7 +2396,7 @@ buildvariants: - matrix_name: "tests-jdk-secure" matrix_spec: { auth: "auth", ssl: "ssl", jdk: [ "jdk8", "jdk17", "jdk21" ], - version: [ "4.2", "4.4", "5.0", "6.0", "7.0", "8.0", "latest" ], + version: [ "4.2", "4.4", "5.0", "6.0", "7.0", "8.0", "9.0", "latest" ], topology: "*", os: "linux" } display_name: "${version} ${topology} ${auth} ${ssl} ${jdk} ${os} " tags: [ "tests-variant" ] @@ -2429,7 +2433,7 @@ buildvariants: exec_timeout_secs: 7200 - matrix_name: "tests-require-api-version" - matrix_spec: { api-version: "required", auth: "auth", ssl: "nossl", jdk: [ "jdk21" ], version: [ "5.0", "6.0", "7.0", "8.0", "latest" ], + matrix_spec: { api-version: "required", auth: "auth", ssl: "nossl", jdk: [ "jdk21" ], version: [ "5.0", "6.0", "7.0", "8.0", "9.0", "latest" ], topology: "standalone", os: "linux" } display_name: "${version} ${topology} ${api-version} " tags: [ "tests-variant" ] @@ -2440,7 +2444,7 @@ buildvariants: - name: "test-legacy-task" - matrix_name: "tests-load-balancer-secure" - matrix_spec: { auth: "auth", ssl: "ssl", jdk: [ "jdk21" ], version: [ "5.0", "6.0", "7.0", "8.0", "latest" ], topology: "sharded-cluster", + matrix_spec: { auth: "auth", ssl: "ssl", jdk: [ "jdk21" ], version: [ "5.0", "6.0", "7.0", "8.0", "9.0", "latest" ], topology: "sharded-cluster", os: "ubuntu" } display_name: "Load Balancer ${version} ${auth} ${ssl} ${jdk} ${os}" tasks: @@ -2500,7 +2504,7 @@ buildvariants: - name: "gssapi-auth-test-task" - matrix_name: "aws-auth-test" - matrix_spec: { ssl: "nossl", jdk: [ "jdk8", "jdk17", "jdk21" ], version: [ "4.4", "5.0", "6.0", "7.0", "8.0", "latest" ], os: "ubuntu", + matrix_spec: { ssl: "nossl", jdk: [ "jdk8", "jdk17", "jdk21" ], version: [ "4.4", "5.0", "6.0", "7.0", "8.0", "9.0", "latest" ], os: "ubuntu", aws-credential-provider: "*" } display_name: "MONGODB-AWS Basic Auth test ${version} ${jdk} ${aws-credential-provider}" run_on: "ubuntu2204-small" @@ -2519,7 +2523,7 @@ buildvariants: - name: "aws-auth-test-with-web-identity-credentials-task" - matrix_name: "accept-api-version-2-test" - matrix_spec: { ssl: "nossl", auth: "noauth", jdk: "jdk21", version: [ "5.0", "6.0", "7.0", "8.0", "latest" ], topology: "standalone", + matrix_spec: { ssl: "nossl", auth: "noauth", jdk: "jdk21", version: [ "5.0", "6.0", "7.0", "8.0", "9.0", "latest" ], topology: "standalone", os: "linux" } display_name: "Accept API Version 2 ${version}" run_on: "ubuntu2204-small" @@ -2527,7 +2531,7 @@ buildvariants: - name: "accept-api-version-2-test-task" - matrix_name: "ocsp-test" - matrix_spec: { auth: "noauth", ssl: "ssl", jdk: "jdk21", version: [ "4.4", "5.0", "6.0", "7.0", "8.0", "latest" ], os: "ubuntu" } + matrix_spec: { auth: "noauth", ssl: "ssl", jdk: "jdk21", version: [ "4.4", "5.0", "6.0", "7.0", "8.0", "9.0", "latest" ], os: "ubuntu" } display_name: "OCSP test ${version} ${os}" tasks: - name: ".ocsp" @@ -2560,14 +2564,14 @@ buildvariants: - name: ".csfle-aws-from-environment" - matrix_name: "csfle-tests-with-mongocryptd" - matrix_spec: { os: "linux", version: [ "4.2", "4.4", "5.0", "6.0", "7.0", "8.0", "latest" ], topology: [ "replicaset" ] } + matrix_spec: { os: "linux", version: [ "4.2", "4.4", "5.0", "6.0", "7.0", "8.0", "9.0", "latest" ], topology: [ "replicaset" ] } display_name: "CSFLE with mongocryptd: ${version}" tasks: - name: "csfle-tests-with-mongocryptd-task" - matrix_name: "csfle-tests-with-mongocryptd-windows" matrix_spec: { os: "windows", - version: [ "8.0", "latest" ], + version: [ "8.0", "9.0", "latest" ], topology: [ "replicaset" ] } display_name: "${os} CSFLE with mongocryptd: ${version}" tasks: diff --git a/driver-core/src/main/com/mongodb/internal/connection/InternalStreamConnectionInitializer.java b/driver-core/src/main/com/mongodb/internal/connection/InternalStreamConnectionInitializer.java index 36f6688cb0e..1af994635f9 100644 --- a/driver-core/src/main/com/mongodb/internal/connection/InternalStreamConnectionInitializer.java +++ b/driver-core/src/main/com/mongodb/internal/connection/InternalStreamConnectionInitializer.java @@ -173,7 +173,7 @@ private InternalConnectionInitializationDescription createInitializationDescript private BsonDocument createHelloCommand(final Authenticator authenticator, final InternalConnection connection) { BsonDocument helloCommandDocument = new BsonDocument(getHandshakeCommandName(), new BsonInt32(1)) .append("helloOk", BsonBoolean.TRUE) - .append("backpressure", BsonBoolean.TRUE); + .append("backpressure", new BsonString("2")); if (clientMetadataDocument != null) { helloCommandDocument.append("client", clientMetadataDocument); } diff --git a/driver-core/src/main/com/mongodb/internal/operation/SpecRetryPolicy.java b/driver-core/src/main/com/mongodb/internal/operation/SpecRetryPolicy.java index 650423c7d5c..6ba8421fff7 100644 --- a/driver-core/src/main/com/mongodb/internal/operation/SpecRetryPolicy.java +++ b/driver-core/src/main/com/mongodb/internal/operation/SpecRetryPolicy.java @@ -16,6 +16,7 @@ package com.mongodb.internal.operation; import com.mongodb.MongoClientSettings; +import com.mongodb.MongoCommandException; import com.mongodb.MongoConnectionPoolClearedException; import com.mongodb.MongoException; import com.mongodb.MongoOperationTimeoutException; @@ -33,6 +34,9 @@ import com.mongodb.internal.time.ExponentialBackoff; import com.mongodb.lang.Nullable; +import org.bson.BsonDocument; +import org.bson.BsonValue; + import java.time.Duration; import java.util.EnumMap; import java.util.EnumSet; @@ -66,6 +70,7 @@ */ final class SpecRetryPolicy implements RetryPolicy { private static final int INFINITE_ATTEMPTS = Integer.MAX_VALUE; + private static final String BASE_BACKOFF_MS_FIELD = "baseBackoffMS"; private final IndividualPolicies policies; private int maxAttempts; @@ -285,11 +290,28 @@ private static Duration calculateOverloadBackoff(final Throwable attemptFailedRe assertFalse(attemptFailedResult instanceof OperationHelper.ResourceSupplierInternalException); if (attemptFailedResult instanceof MongoException && ((MongoException) attemptFailedResult).hasErrorLabel(SYSTEM_OVERLOADED_ERROR_LABEL)) { - return ExponentialBackoff.calculateOverloadBackoff(immediateNextAttempt); + return ExponentialBackoff.calculateOverloadBackoff(immediateNextAttempt, extractBaseBackoffMs(attemptFailedResult)); } return Duration.ZERO; } + @Nullable + private static Long extractBaseBackoffMs(final Throwable attemptFailedResult) { + if (!(attemptFailedResult instanceof MongoCommandException)) { + return null; + } + BsonDocument response = ((MongoCommandException) attemptFailedResult).getResponse(); + if (!response.containsKey(BASE_BACKOFF_MS_FIELD)) { + return null; + } + BsonValue value = response.get(BASE_BACKOFF_MS_FIELD); + if (!value.isNumber()) { + return null; + } + long parsed = value.asNumber().longValue(); + return parsed > 0 ? parsed : null; + } + private static int maxAttempts(final int maxRetries) { if (maxRetries == INFINITE_ATTEMPTS) { return INFINITE_ATTEMPTS; diff --git a/driver-core/src/main/com/mongodb/internal/time/ExponentialBackoff.java b/driver-core/src/main/com/mongodb/internal/time/ExponentialBackoff.java index be2813c5d15..78584778a91 100644 --- a/driver-core/src/main/com/mongodb/internal/time/ExponentialBackoff.java +++ b/driver-core/src/main/com/mongodb/internal/time/ExponentialBackoff.java @@ -18,6 +18,7 @@ import com.mongodb.internal.VisibleForTesting; import com.mongodb.internal.async.function.RetryControl; +import com.mongodb.lang.Nullable; import java.time.Duration; import java.util.concurrent.ThreadLocalRandom; @@ -58,7 +59,20 @@ public static long calculateTransactionBackoffMs(final int attemptNumber) { * See {@link #calculateTransactionBackoffMs(int)} for more details. */ public static Duration calculateOverloadBackoff(final int attemptNumber) { - return Duration.ofMillis(calculateBackoffMs(100, 10000, 2, attemptNumber)); + return calculateOverloadBackoff(attemptNumber, null); + } + + /** + * Calculate the backoff for command retries caused by + * {@linkplain com.mongodb.MongoException#SYSTEM_OVERLOADED_ERROR_LABEL overload}, + * optionally using a server-supplied {@code baseBackoffMs} in place of the 100ms default. + * A {@code null} or non-positive {@code baseBackoffMs} falls back to the default. + * + * @param baseBackoffMs The server-supplied base backoff in milliseconds, or {@code null}. + */ + public static Duration calculateOverloadBackoff(final int attemptNumber, @Nullable final Long baseBackoffMs) { + double baseMs = baseBackoffMs != null && baseBackoffMs > 0 ? baseBackoffMs : 100; + return Duration.ofMillis(calculateBackoffMs(baseMs, 10000, 2, attemptNumber)); } /** @@ -70,7 +84,7 @@ private static long calculateBackoffMs(final double baseMs, final double maxMs, ? testJitterSupplier.getAsDouble() : ThreadLocalRandom.current().nextDouble(); return Math.round(jitter * Math.min( - baseMs * Math.pow(growth, attemptNumber - 1), + baseMs * Math.pow(growth, attemptNumber), maxMs)); } diff --git a/driver-core/src/test/unit/com/mongodb/internal/connection/InternalStreamConnectionInitializerSpecification.groovy b/driver-core/src/test/unit/com/mongodb/internal/connection/InternalStreamConnectionInitializerSpecification.groovy index d3f05ea8b49..4a4b1c0f231 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/connection/InternalStreamConnectionInitializerSpecification.groovy +++ b/driver-core/src/test/unit/com/mongodb/internal/connection/InternalStreamConnectionInitializerSpecification.groovy @@ -201,7 +201,7 @@ class InternalStreamConnectionInitializerSpecification extends Specification { def initializer = new InternalStreamConnectionInitializer(SINGLE, null, clientMetadataDocument, [], null) def expectedHelloCommandDocument = new BsonDocument(LEGACY_HELLO, new BsonInt32(1)) .append('helloOk', BsonBoolean.TRUE) - .append('backpressure', BsonBoolean.TRUE) + .append('backpressure', new BsonString('2')) .append('\$db', new BsonString('admin')) if (clientMetadataDocument != null) { expectedHelloCommandDocument.append('client', clientMetadataDocument) @@ -234,7 +234,7 @@ class InternalStreamConnectionInitializerSpecification extends Specification { def initializer = new InternalStreamConnectionInitializer(SINGLE, null, null, compressors, null) def expectedHelloCommandDocument = new BsonDocument(LEGACY_HELLO, new BsonInt32(1)) .append('helloOk', BsonBoolean.TRUE) - .append('backpressure', BsonBoolean.TRUE) + .append('backpressure', new BsonString('2')) .append('\$db', new BsonString('admin')) def compressionArray = new BsonArray() @@ -405,7 +405,7 @@ class InternalStreamConnectionInitializerSpecification extends Specification { ((SpeculativeAuthenticator) authenticator).getSpeculativeAuthenticateResponse() == null ((SpeculativeAuthenticator) authenticator) .createSpeculativeAuthenticateCommand(internalConnection) == null - BsonDocument.parse("{$LEGACY_HELLO: 1, helloOk: true, backpressure: true, '\$db': 'admin'}") == + BsonDocument.parse("{$LEGACY_HELLO: 1, helloOk: true, backpressure: \"2\", '\$db': 'admin'}") == decodeCommand(internalConnection.getSent()[0]) where: @@ -503,7 +503,7 @@ class InternalStreamConnectionInitializerSpecification extends Specification { def createHelloCommand(final String firstClientChallenge, final String mechanism, final boolean hasSaslSupportedMechs) { - String hello = "{$LEGACY_HELLO: 1, helloOk: true, backpressure: true, " + + String hello = "{$LEGACY_HELLO: 1, helloOk: true, backpressure: \"2\", " + (hasSaslSupportedMechs ? 'saslSupportedMechs: "database.user", ' : '') + (mechanism == 'MONGODB-X509' ? 'speculativeAuthenticate: { authenticate: 1, ' + diff --git a/driver-core/src/test/unit/com/mongodb/internal/time/ExponentialBackoffTest.java b/driver-core/src/test/unit/com/mongodb/internal/time/ExponentialBackoffTest.java index 504a9840e73..d4686e05827 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/time/ExponentialBackoffTest.java +++ b/driver-core/src/test/unit/com/mongodb/internal/time/ExponentialBackoffTest.java @@ -28,8 +28,8 @@ class ExponentialBackoffTest { * Expected {@linkplain ExponentialBackoff#calculateTransactionBackoffMs(int) backoffs} with 1.0 as * {@link ExponentialBackoff#setTestJitterSupplier(DoubleSupplier) jitter}. */ - private static final double[] EXPECTED_BACKOFFS_MAX_VALUES = {5.0, 7.5, 11.25, 16.875, 25.3125, 37.96875, 56.953125, 85.4296875, 128.14453125, - 192.21679688, 288.32519531, 432.48779297, 500.0}; + private static final double[] EXPECTED_BACKOFFS_MAX_VALUES = {7.5, 11.25, 16.875, 25.3125, 37.96875, 56.953125, 85.4296875, 128.14453125, + 192.21679688, 288.32519531, 432.48779297, 500.0, 500.0}; @Test void testCalculateTransactionBackoffMs() { @@ -79,4 +79,52 @@ void testCalculateTransactionBackoffMsWithJitterZero() { ExponentialBackoff.clearTestJitterSupplier(); } } + + @Test + void testCalculateOverloadBackoffUsesDefaultBaseWhenOverrideAbsent() { + ExponentialBackoff.setTestJitterSupplier(() -> 1.0); + try { + // 100 * 2^1 = 200, 100 * 2^2 = 400 + assertEquals(200L, ExponentialBackoff.calculateOverloadBackoff(1).toMillis()); + assertEquals(400L, ExponentialBackoff.calculateOverloadBackoff(2).toMillis()); + // null override == default + assertEquals(200L, ExponentialBackoff.calculateOverloadBackoff(1, null).toMillis()); + } finally { + ExponentialBackoff.clearTestJitterSupplier(); + } + } + + @Test + void testCalculateOverloadBackoffUsesServerBaseBackoffMsWhenPositive() { + ExponentialBackoff.setTestJitterSupplier(() -> 1.0); + try { + // 50 * 2^1 = 100, 50 * 2^2 = 200 + assertEquals(100L, ExponentialBackoff.calculateOverloadBackoff(1, 50L).toMillis()); + assertEquals(200L, ExponentialBackoff.calculateOverloadBackoff(2, 50L).toMillis()); + } finally { + ExponentialBackoff.clearTestJitterSupplier(); + } + } + + @Test + void testCalculateOverloadBackoffIgnoresNonPositiveOverride() { + ExponentialBackoff.setTestJitterSupplier(() -> 1.0); + try { + assertEquals(200L, ExponentialBackoff.calculateOverloadBackoff(1, 0L).toMillis()); + assertEquals(200L, ExponentialBackoff.calculateOverloadBackoff(1, -10L).toMillis()); + } finally { + ExponentialBackoff.clearTestJitterSupplier(); + } + } + + @Test + void testCalculateOverloadBackoffRespectsMaxCapWithLargeBaseBackoffMs() { + ExponentialBackoff.setTestJitterSupplier(() -> 1.0); + try { + // base 20000 * 2^1 = 40000 -> capped at 10000 + assertEquals(10000L, ExponentialBackoff.calculateOverloadBackoff(1, 20000L).toMillis()); + } finally { + ExponentialBackoff.clearTestJitterSupplier(); + } + } } diff --git a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientMetadataProseTest.java b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientMetadataProseTest.java index 320f79e54b2..865b4492294 100644 --- a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientMetadataProseTest.java +++ b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientMetadataProseTest.java @@ -24,8 +24,8 @@ import com.mongodb.internal.connection.TestCommandListener; import com.mongodb.internal.connection.TestConnectionPoolListener; import com.mongodb.lang.Nullable; -import org.bson.BsonBoolean; import org.bson.BsonDocument; +import org.bson.BsonString; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; @@ -335,9 +335,9 @@ void testEmptyStringsAreConsideredUnsetWhenAppendingMetadataIdenticalToInitialMe } } - @DisplayName("Test 9: Handshake documents include backpressure: true") + @DisplayName("Test 9: Handshake documents include backpressure: \"2\"") @Test - void testHandshakeDocumentsIncludeBackpressureTrue() { + void testHandshakeDocumentsIncludeBackpressureTwo() { try (MongoClient mongoClient = createMongoClient(null, getMongoClientSettings())) { commandListener.reset(); mongoClient.getDatabase("admin").runCommand(BsonDocument.parse("{ping: 1}")); @@ -346,10 +346,8 @@ void testHandshakeDocumentsIncludeBackpressureTrue() { assertFalse(handshakeEvents.isEmpty(), "Expected at least one handshake document to be captured"); for (CommandStartedEvent event : handshakeEvents) { BsonDocument helloCommand = event.getCommand(); - assertTrue(helloCommand.containsKey("backpressure"), - "Handshake document is missing 'backpressure' field"); - assertEquals(BsonBoolean.TRUE, helloCommand.getBoolean("backpressure"), - "Handshake document 'backpressure' field is not true"); + assertEquals(new BsonString("2"), helloCommand.get("backpressure"), + "Handshake document 'backpressure' field is not the string \"2\""); } } } diff --git a/driver-sync/src/test/functional/com/mongodb/client/BackpressureProseTest.java b/driver-sync/src/test/functional/com/mongodb/client/BackpressureProseTest.java index bb566ed2fe4..07bdc7f4579 100644 --- a/driver-sync/src/test/functional/com/mongodb/client/BackpressureProseTest.java +++ b/driver-sync/src/test/functional/com/mongodb/client/BackpressureProseTest.java @@ -117,8 +117,8 @@ void operationRetryUsesExponentialBackoff() throws InterruptedException { MongoCollection collection = dropAndGetCollection("operationRetryUsesExponentialBackoff", client); long noBackoffTimeMillis = measureFailedInsertDuration(collection, false).toMillis(); long withBackoffTimeMillis = measureFailedInsertDuration(collection, true).toMillis(); - long expectedMaxVarianceMillis = 300; - long maxTotalBackoffMillis = 300; + long expectedMaxVarianceMillis = 600; + long maxTotalBackoffMillis = 600; long actualAbsDiffMillis = Math.abs(withBackoffTimeMillis - (noBackoffTimeMillis + maxTotalBackoffMillis)); assertTrue(actualAbsDiffMillis < expectedMaxVarianceMillis, format("Expected actualAbsDiffMillis < %d ms, but was %d ms (|%d ms - (%d ms + %d ms)|)", @@ -137,6 +137,57 @@ private static Duration measureFailedInsertDuration(final MongoCollection collection) { + StartTime startTime = StartTime.now(); + assertThrows(MongoServerException.class, () -> collection.insertOne(Document.parse("{a: 1}"))); + return startTime.elapsed(); + } + + /** + * + * Test 5: Overload Errors with baseBackoffMS override base backoff. + */ + @Test + void overloadErrorsWithBaseBackoffMsOverrideBaseBackoff() throws InterruptedException { + assumeTrue(serverVersionAtLeast(9, 0)); + BsonDocument configureFailPoint = BsonDocument.parse( + "{\n" + + " configureFailPoint: 'failCommand',\n" + + " mode: 'alwaysOn',\n" + + " data: {\n" + + " failCommands: ['insert'],\n" + + " errorCode: 462,\n" + + " errorLabels: ['" + SYSTEM_OVERLOADED_ERROR_LABEL + "', '" + RETRYABLE_ERROR_LABEL + "']\n" + + " }\n" + + "}\n"); + try (MongoClient client = createClient(getMongoClientSettings()); + FailPoint ignored = FailPoint.enable(configureFailPoint, getPrimary())) { + MongoCollection collection = dropAndGetCollection("overloadErrorsWithBaseBackoffMsOverrideBaseBackoff", client); + + ExponentialBackoff.setTestJitterSupplier(() -> 1); + try { + long exponentialBackoffTimeMs = measureFailedInsertDuration(collection).toMillis(); + + client.getDatabase("admin").runCommand(Document.parse("{setParameter: 1, externalClientBaseBackoffMS: 50}")); + long withBaseBackoffMsTimeMs; + try { + withBaseBackoffMsTimeMs = measureFailedInsertDuration(collection).toMillis(); + } finally { + client.getDatabase("admin").runCommand(Document.parse("{setParameter: 1, externalClientBaseBackoffMS: 0}")); + } + + assertTrue(exponentialBackoffTimeMs >= 600, + format("Expected default-backoff run >= 600 ms, was %d ms", exponentialBackoffTimeMs)); + assertTrue(withBaseBackoffMsTimeMs >= 300, + format("Expected baseBackoffMS=50 run >= 300 ms, was %d ms", withBaseBackoffMsTimeMs)); + assertTrue(withBaseBackoffMsTimeMs < 600, + format("Expected baseBackoffMS=50 run < 600 ms, was %d ms", withBaseBackoffMsTimeMs)); + } finally { + ExponentialBackoff.clearTestJitterSupplier(); + } + } + } + /** * * Test 3: Overload Errors are Retried a Maximum of {@code MAX_RETRIES} times. diff --git a/driver-sync/src/test/functional/com/mongodb/client/WithTransactionProseTest.java b/driver-sync/src/test/functional/com/mongodb/client/WithTransactionProseTest.java index 6d2b928e8ec..d726adfa9b3 100644 --- a/driver-sync/src/test/functional/com/mongodb/client/WithTransactionProseTest.java +++ b/driver-sync/src/test/functional/com/mongodb/client/WithTransactionProseTest.java @@ -235,7 +235,7 @@ public void testRetryBackoffIsEnforced() throws InterruptedException { long noBackoffTimeMs = measureTransactionLatencyMs(0.0); long withBackoffTimeMs = measureTransactionLatencyMs(1.0); - long sumOfBackoffsMs = 1800; + long sumOfBackoffsMs = 2300; long toleranceMs = 500; long actualDifferenceMs = Math.abs(withBackoffTimeMs - (noBackoffTimeMs + sumOfBackoffsMs));