Skip to content

Commit b33dca9

Browse files
authored
Add MongoException.SYSTEM_OVERLOADED_ERROR_LABEL/RETRYABLE_ERROR_LABEL (#1926)
This commit only adds the labels, and does not fully implement the tickets specified below. The reason there are four JAVA tickets specified is that the is a single specification commit that resolved the four corresponding DRIVERS tickets. All of these JAVA tickets have to be done together. The relevant spec changes: - https://github.com/mongodb/specifications/blame/ba14b6bdc1dc695aa9cc20ccf9378592da1b2329/source/client-backpressure/client-backpressure.md#L52-L80 - it's a subset of [DRIVERS-3239, DRIVERS-3411, DRIVERS-3370, DRIVERS-3412: Client backpressure (#1907)](mongodb/specifications@1125200) JAVA-5956, JAVA-6117, JAVA-6113, JAVA-6119
1 parent ac1c120 commit b33dca9

File tree

7 files changed

+71
-40
lines changed

7 files changed

+71
-40
lines changed

driver-core/src/main/com/mongodb/MongoException.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public class MongoException extends RuntimeException {
3939
*
4040
* @see #hasErrorLabel(String)
4141
* @since 3.8
42+
* @mongodb.driver.manual core/transactions-in-applications/#std-label-transient-transaction-error
4243
*/
4344
public static final String TRANSIENT_TRANSACTION_ERROR_LABEL = "TransientTransactionError";
4445

@@ -47,9 +48,32 @@ public class MongoException extends RuntimeException {
4748
*
4849
* @see #hasErrorLabel(String)
4950
* @since 3.8
51+
* @mongodb.driver.manual core/transactions-in-applications/#std-label-unknown-transaction-commit-result
5052
*/
5153
public static final String UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL = "UnknownTransactionCommitResult";
5254

55+
/**
56+
* Server is overloaded and shedding load.
57+
* If you retry, use exponential backoff because the server has indicated overload.
58+
* This label on its own does not mean that the operation can be safely retried.
59+
*
60+
* @see #hasErrorLabel(String)
61+
* @since 5.7
62+
* @mongodb.server.release 8.3
63+
*/
64+
// TODO-BACKPRESSURE Valentin Add a @mongodb.driver.manual link or something similar, see `content/atlas/source/overload-errors.txt` in https://github.com/10gen/docs-mongodb-internal/pull/17281
65+
public static final String SYSTEM_OVERLOADED_ERROR_LABEL = "SystemOverloadedError";
66+
67+
/**
68+
* The operation was not executed and is safe to retry.
69+
*
70+
* @see #hasErrorLabel(String)
71+
* @since 5.7
72+
* @mongodb.server.release 8.3
73+
*/
74+
// TODO-BACKPRESSURE Valentin Add a @mongodb.driver.manual link or something similar, see `content/atlas/source/overload-errors.txt` in https://github.com/10gen/docs-mongodb-internal/pull/17281
75+
public static final String RETRYABLE_ERROR_LABEL = "RetryableError";
76+
5377
private static final long serialVersionUID = -4415279469780082174L;
5478

5579
private final int code;

driver-core/src/main/com/mongodb/internal/operation/CommandOperationHelper.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
import static java.util.Arrays.asList;
5252

5353
@SuppressWarnings("overloads")
54-
final class CommandOperationHelper {
54+
public final class CommandOperationHelper {
5555
static WriteConcern validateAndGetEffectiveWriteConcern(final WriteConcern writeConcernSetting, final SessionContext sessionContext)
5656
throws MongoClientException {
5757
boolean activeTransaction = sessionContext.hasActiveTransaction();
@@ -223,8 +223,8 @@ static boolean isRetryWritesEnabled(@Nullable final BsonDocument command) {
223223
|| command.getFirstKey().equals("commitTransaction") || command.getFirstKey().equals("abortTransaction")));
224224
}
225225

226-
static final String RETRYABLE_WRITE_ERROR_LABEL = "RetryableWriteError";
227-
private static final String NO_WRITES_PERFORMED_ERROR_LABEL = "NoWritesPerformed";
226+
public static final String RETRYABLE_WRITE_ERROR_LABEL = "RetryableWriteError";
227+
public static final String NO_WRITES_PERFORMED_ERROR_LABEL = "NoWritesPerformed";
228228

229229
private static boolean decideRetryableAndAddRetryableWriteErrorLabel(final Throwable t, @Nullable final Integer maxWireVersion) {
230230
if (!(t instanceof MongoException)) {

driver-sync/src/examples/documentation/TransactionExample.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ private void runTransactionWithRetry(final Runnable transactional) {
7777
System.out.println("Transaction aborted. Caught exception during transaction.");
7878

7979
if (e.hasErrorLabel(MongoException.TRANSIENT_TRANSACTION_ERROR_LABEL)) {
80-
System.out.println("TransientTransactionError, aborting transaction and retrying ...");
80+
System.out.printf("%s, aborting transaction and retrying ...%n",
81+
MongoException.TRANSIENT_TRANSACTION_ERROR_LABEL);
8182
} else {
8283
throw e;
8384
}
@@ -94,7 +95,8 @@ private void commitWithRetry(final ClientSession clientSession) {
9495
} catch (MongoException e) {
9596
// can retry commit
9697
if (e.hasErrorLabel(MongoException.UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL)) {
97-
System.out.println("UnknownTransactionCommitResult, retrying commit operation ...");
98+
System.out.printf("%s, retrying commit operation ...%n",
99+
MongoException.UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL);
98100
} else {
99101
System.out.println("Exception during commit ...");
100102
throw e;

driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import com.mongodb.event.ConnectionCreatedEvent;
4949
import com.mongodb.event.ConnectionReadyEvent;
5050

51+
import static com.mongodb.MongoException.TRANSIENT_TRANSACTION_ERROR_LABEL;
5152
import static com.mongodb.internal.connection.CommandHelper.HELLO;
5253
import static com.mongodb.internal.connection.CommandHelper.LEGACY_HELLO;
5354

@@ -687,7 +688,7 @@ public void test10CustomTestWithTransactionUsesASingleTimeoutWithLock() {
687688
+ " blockConnection: true,"
688689
+ " blockTimeMS: " + 25
689690
+ " errorCode: " + 24
690-
+ " errorLabels: [\"TransientTransactionError\"]"
691+
+ " errorLabels: [\"" + TRANSIENT_TRANSACTION_ERROR_LABEL + "\"]"
691692
+ " }"
692693
+ "}");
693694

driver-sync/src/test/functional/com/mongodb/client/MongoWriteConcernWithResponseExceptionTest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343
import static com.mongodb.ClusterFixture.serverVersionAtLeast;
4444
import static com.mongodb.client.Fixture.getDefaultDatabaseName;
4545
import static com.mongodb.client.Fixture.getMongoClientSettingsBuilder;
46+
import static com.mongodb.internal.operation.CommandOperationHelper.NO_WRITES_PERFORMED_ERROR_LABEL;
47+
import static com.mongodb.internal.operation.CommandOperationHelper.RETRYABLE_WRITE_ERROR_LABEL;
4648
import static java.util.Collections.singletonList;
4749
import static org.junit.Assert.assertThrows;
4850
import static org.junit.Assume.assumeTrue;
@@ -69,7 +71,7 @@ public static void doesNotLeak(final Function<MongoClientSettings, MongoClient>
6971
.append("data", new BsonDocument()
7072
.append("writeConcernError", new BsonDocument()
7173
.append("code", new BsonInt32(91))
72-
.append("errorLabels", new BsonArray(Stream.of("RetryableWriteError")
74+
.append("errorLabels", new BsonArray(Stream.of(RETRYABLE_WRITE_ERROR_LABEL)
7375
.map(BsonString::new).collect(Collectors.toList())))
7476
.append("errmsg", new BsonString(""))
7577
)
@@ -81,7 +83,7 @@ public static void doesNotLeak(final Function<MongoClientSettings, MongoClient>
8183
.append("data", new BsonDocument()
8284
.append("failCommands", new BsonArray(singletonList(new BsonString("insert"))))
8385
.append("errorCode", new BsonInt32(10107))
84-
.append("errorLabels", new BsonArray(Stream.of("RetryableWriteError", "NoWritesPerformed")
86+
.append("errorLabels", new BsonArray(Stream.of(RETRYABLE_WRITE_ERROR_LABEL, NO_WRITES_PERFORMED_ERROR_LABEL)
8587
.map(BsonString::new).collect(Collectors.toList()))));
8688
doesNotLeak(clientCreator, writeConcernErrorFpDoc, true, noWritesPerformedFpDoc);
8789
doesNotLeak(clientCreator, noWritesPerformedFpDoc, false, writeConcernErrorFpDoc);

driver-sync/src/test/functional/com/mongodb/client/RetryableWritesProseTest.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@
6767
import static com.mongodb.client.Fixture.getDefaultDatabaseName;
6868
import static com.mongodb.client.Fixture.getMongoClientSettingsBuilder;
6969
import static com.mongodb.client.Fixture.getMultiMongosMongoClientSettingsBuilder;
70+
import static com.mongodb.internal.operation.CommandOperationHelper.NO_WRITES_PERFORMED_ERROR_LABEL;
71+
import static com.mongodb.internal.operation.CommandOperationHelper.RETRYABLE_WRITE_ERROR_LABEL;
7072
import static java.util.Arrays.asList;
7173
import static java.util.Collections.emptyList;
7274
import static java.util.Collections.singletonList;
@@ -135,7 +137,7 @@ public static <R> void poolClearedExceptionMustBeRetryable(
135137
.append("failCommands", new BsonArray(singletonList(new BsonString(operationName))))
136138
.append("errorCode", new BsonInt32(91))
137139
.append("errorLabels", write
138-
? new BsonArray(singletonList(new BsonString("RetryableWriteError")))
140+
? new BsonArray(singletonList(new BsonString(RETRYABLE_WRITE_ERROR_LABEL)))
139141
: new BsonArray())
140142
.append("blockConnection", BsonBoolean.valueOf(true))
141143
.append("blockTimeMS", new BsonInt32(1000)));
@@ -193,7 +195,7 @@ public void commandSucceeded(final CommandSucceededEvent event) {
193195
.append("data", new BsonDocument()
194196
.append("failCommands", new BsonArray(singletonList(new BsonString("insert"))))
195197
.append("errorCode", new BsonInt32(10107))
196-
.append("errorLabels", new BsonArray(Stream.of("RetryableWriteError", "NoWritesPerformed")
198+
.append("errorLabels", new BsonArray(Stream.of(RETRYABLE_WRITE_ERROR_LABEL, NO_WRITES_PERFORMED_ERROR_LABEL)
197199
.map(BsonString::new).collect(Collectors.toList())))),
198200
primaryServerAddress
199201
)));
@@ -207,7 +209,7 @@ public void commandSucceeded(final CommandSucceededEvent event) {
207209
.append("data", new BsonDocument()
208210
.append("writeConcernError", new BsonDocument()
209211
.append("code", new BsonInt32(91))
210-
.append("errorLabels", new BsonArray(Stream.of("RetryableWriteError")
212+
.append("errorLabels", new BsonArray(Stream.of(RETRYABLE_WRITE_ERROR_LABEL)
211213
.map(BsonString::new).collect(Collectors.toList())))
212214
.append("errmsg", new BsonString(""))
213215
)

driver-sync/src/test/functional/com/mongodb/client/WithTransactionProseTest.java

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@
3737
import static org.junit.jupiter.api.Assertions.fail;
3838
import static org.junit.jupiter.api.Assumptions.assumeTrue;
3939

40-
// See https://github.com/mongodb/specifications/blob/master/source/transactions-convenient-api/tests/README.md#prose-tests
40+
/**
41+
* <a href="https://github.com/mongodb/specifications/blob/master/source/transactions-convenient-api/tests/README.md#prose-tests">Prose Tests</a>.
42+
*/
4143
public class WithTransactionProseTest extends DatabaseTestCase {
4244
private static final long START_TIME_MS = 1L;
4345
private static final long ERROR_GENERATING_INTERVAL = 121000L;
@@ -52,11 +54,10 @@ public void setUp() {
5254
collection.insertOne(Document.parse("{ _id : 0 }"));
5355
}
5456

55-
//
56-
// Test that the callback raises a custom exception or error that does not include either UnknownTransactionCommitResult or
57-
// TransientTransactionError error labels. The callback will execute using withTransaction and assert that the callback's error
58-
// bypasses any retry logic within withTransaction and is propagated to the caller of withTransaction.
59-
//
57+
/**
58+
* <a href="https://github.com/mongodb/specifications/blob/master/source/transactions-convenient-api/tests/README.md#callback-raises-a-custom-error">
59+
* Callback Raises a Custom Error</a>.
60+
*/
6061
@Test
6162
public void testCallbackRaisesCustomError() {
6263
final String exceptionMessage = "NotTransientOrUnknownError";
@@ -71,10 +72,10 @@ public void testCallbackRaisesCustomError() {
7172
}
7273
}
7374

74-
//
75-
// Test that the callback that returns a custom value (e.g. boolean, string, object). Execute this callback using withTransaction
76-
// and assert that the callback's return value is propagated to the caller of withTransaction.
77-
//
75+
/**
76+
* <a href="https://github.com/mongodb/specifications/blob/master/source/transactions-convenient-api/tests/README.md#callback-returns-a-value">
77+
* Callback Returns a Value</a>.
78+
*/
7879
@Test
7980
public void testCallbackReturnsValue() {
8081
try (ClientSession session = client.startSession()) {
@@ -87,10 +88,10 @@ public void testCallbackReturnsValue() {
8788
}
8889
}
8990

90-
//
91-
// If the callback raises an error with the TransientTransactionError label and the retry timeout has been exceeded, withTransaction
92-
// should propagate the error to its caller.
93-
//
91+
/**
92+
* <a href="https://github.com/mongodb/specifications/blob/master/source/transactions-convenient-api/tests/README.md#retry-timeout-is-enforced">
93+
* Retry Timeout is Enforced</a>, first scenario on the list.
94+
*/
9495
@Test
9596
public void testRetryTimeoutEnforcedTransientTransactionError() {
9697
final String errorMessage = "transient transaction error";
@@ -110,10 +111,10 @@ public void testRetryTimeoutEnforcedTransientTransactionError() {
110111
}
111112
}
112113

113-
//
114-
// If committing raises an error with the UnknownTransactionCommitResult label, the error is not a write concern timeout, and the
115-
// retry timeout has been exceeded, withTransaction should propagate the error to its caller.
116-
//
114+
/**
115+
* <a href="https://github.com/mongodb/specifications/blob/master/source/transactions-convenient-api/tests/README.md#retry-timeout-is-enforced">
116+
* Retry Timeout is Enforced</a>, second scenario on the list.
117+
*/
117118
@Test
118119
public void testRetryTimeoutEnforcedUnknownTransactionCommit() {
119120
MongoDatabase failPointAdminDb = client.getDatabase("admin");
@@ -137,11 +138,10 @@ public void testRetryTimeoutEnforcedUnknownTransactionCommit() {
137138
}
138139
}
139140

140-
//
141-
// If committing raises an error with the TransientTransactionError label and the retry timeout has been exceeded, withTransaction
142-
// should propagate the error to its caller. This case may occur if the commit was internally retried against a new primary after
143-
// a failover and the second primary returned a NoSuchTransaction error response.
144-
//
141+
/**
142+
* <a href="https://github.com/mongodb/specifications/blob/master/source/transactions-convenient-api/tests/README.md#retry-timeout-is-enforced">
143+
* Retry Timeout is Enforced</a>, third scenario on the list.
144+
*/
145145
@Test
146146
public void testRetryTimeoutEnforcedTransientTransactionErrorOnCommit() {
147147
MongoDatabase failPointAdminDb = client.getDatabase("admin");
@@ -166,9 +166,9 @@ public void testRetryTimeoutEnforcedTransientTransactionErrorOnCommit() {
166166
}
167167
}
168168

169-
//
170-
// Ensure cannot override timeout in transaction
171-
//
169+
/**
170+
* Ensure cannot override timeout in transaction.
171+
*/
172172
@Test
173173
public void testTimeoutMS() {
174174
try (ClientSession session = client.startSession(ClientSessionOptions.builder()
@@ -182,9 +182,9 @@ public void testTimeoutMS() {
182182
}
183183
}
184184

185-
//
186-
// Ensure legacy settings don't cause issues in sessions
187-
//
185+
/**
186+
* Ensure legacy settings don't cause issues in sessions.
187+
*/
188188
@Test
189189
public void testTimeoutMSAndLegacySettings() {
190190
try (ClientSession session = client.startSession(ClientSessionOptions.builder()

0 commit comments

Comments
 (0)