diff --git a/driver-core/src/main/com/mongodb/internal/TimeoutContext.java b/driver-core/src/main/com/mongodb/internal/TimeoutContext.java index 35ffedbb16f..2a886704cd9 100644 --- a/driver-core/src/main/com/mongodb/internal/TimeoutContext.java +++ b/driver-core/src/main/com/mongodb/internal/TimeoutContext.java @@ -192,7 +192,10 @@ public long getMaxAwaitTimeMS() { public void runMaxTimeMS(final LongConsumer onRemaining) { if (maxTimeSupplier != null) { - runWithFixedTimeout(maxTimeSupplier.get(), onRemaining); + long maxTimeMS = maxTimeSupplier.get(); + if (maxTimeMS > 0) { + runMinTimeout(onRemaining, maxTimeMS); + } return; } if (timeout == null) { @@ -209,6 +212,22 @@ public void runMaxTimeMS(final LongConsumer onRemaining) { } + private void runMinTimeout(final LongConsumer onRemaining, final long fixedMs) { + Timeout timeout = timeoutIncludingRoundTrip(); + if (timeout != null) { + timeout.run(MILLISECONDS, () -> { + onRemaining.accept(fixedMs); + }, + (renamingMs) -> { + onRemaining.accept(Math.min(renamingMs, fixedMs)); + }, () -> { + throwMongoTimeoutException("The operation exceeded the timeout limit."); + }); + } else { + onRemaining.accept(fixedMs); + } + } + private static void runWithFixedTimeout(final long ms, final LongConsumer onRemaining) { if (ms != 0) { onRemaining.accept(ms); @@ -227,10 +246,14 @@ public void resetToDefaultMaxTime() { *
* NOTE: Suitable for static user-defined values only (i.e MaxAwaitTimeMS),
* not for running timeouts that adjust dynamically (CSOT).
+ *
+ * If remaining CSOT timeout is less than this static timeout, then CSOT timeout will be used.
+ *
*/
public void setMaxTimeOverride(final long maxTimeMS) {
this.maxTimeSupplier = () -> maxTimeMS;
}
+
/**
* Disable the maxTimeMS override. This way the maxTimeMS will not
* be appended to the command in the {@link CommandMessage}.
diff --git a/driver-core/src/test/resources/unified-test-format/client-side-operation-timeout/tailable-awaitData.json b/driver-core/src/test/resources/unified-test-format/client-side-operation-timeout/tailable-awaitData.json
index d0fe950dd8e..a29e7b3a867 100644
--- a/driver-core/src/test/resources/unified-test-format/client-side-operation-timeout/tailable-awaitData.json
+++ b/driver-core/src/test/resources/unified-test-format/client-side-operation-timeout/tailable-awaitData.json
@@ -4,7 +4,8 @@
"schemaVersion": "1.9",
"runOnRequirements": [
{
- "minServerVersion": "4.4"
+ "minServerVersion": "4.4",
+ "serverless": "forbid"
}
],
"createEntities": [
@@ -419,6 +420,141 @@
]
}
]
+ },
+ {
+ "description": "apply remaining timeoutMS if less than maxAwaitTimeMS",
+ "operations": [
+ {
+ "name": "failPoint",
+ "object": "testRunner",
+ "arguments": {
+ "client": "failPointClient",
+ "failPoint": {
+ "configureFailPoint": "failCommand",
+ "mode": {
+ "times": 1
+ },
+ "data": {
+ "failCommands": [
+ "getMore"
+ ],
+ "blockConnection": true,
+ "blockTimeMS": 30
+ }
+ }
+ }
+ },
+ {
+ "name": "createFindCursor",
+ "object": "collection",
+ "arguments": {
+ "filter": {
+ "_id": 1
+ },
+ "cursorType": "tailableAwait",
+ "batchSize": 1,
+ "maxAwaitTimeMS": 100,
+ "timeoutMS": 200
+ },
+ "saveResultAsEntity": "tailableCursor"
+ },
+ {
+ "name": "iterateOnce",
+ "object": "tailableCursor"
+ },
+ {
+ "name": "iterateUntilDocumentOrError",
+ "object": "tailableCursor",
+ "expectError": {
+ "isTimeoutError": true
+ }
+ }
+ ],
+ "expectEvents": [
+ {
+ "client": "client",
+ "ignoreExtraEvents": true,
+ "events": [
+ {
+ "commandStartedEvent": {
+ "commandName": "find",
+ "databaseName": "test"
+ }
+ },
+ {
+ "commandStartedEvent": {
+ "commandName": "getMore",
+ "databaseName": "test",
+ "command": {
+ "maxTimeMS": {
+ "$$lte": 100
+ }
+ }
+ }
+ },
+ {
+ "commandStartedEvent": {
+ "commandName": "getMore",
+ "databaseName": "test",
+ "command": {
+ "maxTimeMS": {
+ "$$lte": 70
+ }
+ }
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "description": "apply maxAwaitTimeMS if less than remaining timeout",
+ "operations": [
+ {
+ "name": "createFindCursor",
+ "object": "collection",
+ "arguments": {
+ "filter": {},
+ "cursorType": "tailableAwait",
+ "batchSize": 1,
+ "maxAwaitTimeMS": 100,
+ "timeoutMS": 200
+ },
+ "saveResultAsEntity": "tailableCursor"
+ },
+ {
+ "name": "iterateOnce",
+ "object": "tailableCursor"
+ },
+ {
+ "name": "iterateOnce",
+ "object": "tailableCursor"
+ }
+ ],
+ "expectEvents": [
+ {
+ "client": "client",
+ "events": [
+ {
+ "commandStartedEvent": {
+ "commandName": "find",
+ "databaseName": "test"
+ }
+ },
+ {
+ "commandStartedEvent": {
+ "commandName": "getMore",
+ "databaseName": "test",
+ "command": {
+ "maxTimeMS": {
+ "$$lte": 100
+ }
+ }
+ }
+ }
+ ]
+ }
+ ]
}
]
-}
+}
\ No newline at end of file
diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java
index df9706b8dd7..31b8ebb3bdf 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java
@@ -65,6 +65,10 @@ public static void applyCustomizations(final TestDef def) {
// client-side-operation-timeout (CSOT)
+ def.skipNoncompliantReactive("No good way to fulfill tryNext() requirement with a Publisher