-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Yield429 #47406
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Yield429 #47406
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||
| // Licensed under the MIT License. | ||
|
|
||
| package com.azure.cosmos.implementation; | ||
|
|
||
| import com.azure.cosmos.*; | ||
| import com.azure.cosmos.implementation.clienttelemetry.ClientTelemetry; | ||
| import com.azure.cosmos.implementation.directconnectivity.ReflectionUtils; | ||
| import com.azure.cosmos.implementation.directconnectivity.WFConstants; | ||
| import com.azure.cosmos.implementation.routing.PartitionKeyInternal; | ||
| import com.azure.cosmos.models.CosmosClientTelemetryConfig; | ||
| import com.azure.cosmos.models.CosmosQueryRequestOptions; | ||
| import com.azure.cosmos.models.FeedResponse; | ||
| import com.azure.cosmos.models.PartitionKey; | ||
| import com.azure.cosmos.test.faultinjection.*; | ||
| import org.apache.commons.lang3.Range; | ||
| import org.testng.annotations.DataProvider; | ||
| import org.testng.annotations.Test; | ||
| import reactor.core.publisher.Flux; | ||
| import reactor.core.publisher.Mono; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import java.util.UUID; | ||
|
|
||
| import static org.assertj.core.api.Assertions.assertThat; | ||
|
|
||
| public class ConsistencyTestsStrong { | ||
|
|
||
| @Test(groups = {"direct"}) | ||
| public void injectTooManyRequestsFaultAndVerify429Count(boolean shouldRegionScopedSessionContainerEnabled) throws InterruptedException { | ||
| string databaseName = "newdatabase"; | ||
|
|
||
| // Create a fault injection rule for TooManyRequests (429) in direct mode | ||
| FaultInjectionRule tooManyRequestsRule = new FaultInjectionRuleBuilder( | ||
| id: "TooManyRequestsRule-" + Guid.NewGuid(), | ||
| condition: new FaultInjectionConditionBuilder() | ||
| .WithOperationType(FaultInjectionOperationType.ReadItem) | ||
| .Build(), | ||
| result: FaultInjectionResultBuilder.GetResultBuilder(FaultInjectionServerErrorType.TooManyRequests) | ||
| .Build()) | ||
| .Build(); | ||
| // inject 404/1002 into all regions | ||
| FaultInjectionRule tooManyRequestsRule = new FaultInjectionRuleBuilder("tooManyRequestsRule-" + UUID.randomUUID()) | ||
| .condition(new FaultInjectionConditionBuilder()) | ||
| .withOperationType(FaultInjectionOperationType.READ_ITEM) | ||
| .result( | ||
| FaultInjectionResultBuilders | ||
| .getResultBuilder(FaultInjectionServerErrorType.READ_SESSION_NOT_AVAILABLE) | ||
| .build()) | ||
| .build(); | ||
| // Initialize the fault injector | ||
| FaultInjector faultInjector = new FaultInjector(new List<FaultInjectionRule> { tooManyRequestsRule }); | ||
| CosmosClient cosmosClient = new CosmosClientBuilder( | ||
| connectionString: "") | ||
| .WithConnectionModeDirect().WithFaultInjection(faultInjector) | ||
| .WithConsistencyLevel(Cosmos.ConsistencyLevel.Eventual) | ||
| .WithThrottlingRetryOptions( | ||
| maxRetryWaitTimeOnThrottledRequests: TimeSpan.FromSeconds(5), // Maximum wait time for retries | ||
| maxRetryAttemptsOnThrottledRequests: 2) // Maximum retry attempts | ||
| .Build(); | ||
| ContainerProperties containerProperties = new ContainerProperties( | ||
| id: "test", | ||
| partitionKeyPath: "/id"); | ||
| // Create database and container | ||
| await cosmosClient.CreateDatabaseIfNotExistsAsync(databaseName); | ||
| Container container = await cosmosClient.GetDatabase(databaseName).CreateContainerIfNotExistsAsync(containerProperties); | ||
| dynamic testObject = new | ||
| { | ||
| id = Guid.NewGuid().ToString(), | ||
| Company = "Microsoft", | ||
| State = "WA" | ||
|
|
||
| }; | ||
|
|
||
|
|
||
| await container.CreateItemAsync<dynamic>(testObject); | ||
| try | ||
| { | ||
| // Attempt to read the item | ||
| ItemResponse<dynamic> itemResponse = await container.ReadItemAsync<dynamic>( | ||
| testObject.id, | ||
| new Cosmos.PartitionKey(testObject.id)); | ||
|
|
||
| // Print diagnostics | ||
| Console.WriteLine("Diagnostics:"); | ||
| Console.WriteLine(itemResponse.Diagnostics.ToString()); | ||
| } | ||
|
|
||
| catch (CosmosException ex) | ||
| { | ||
| // Handle other Cosmos exceptions | ||
| Console.WriteLine($"CosmosException: {ex.StatusCode} - {ex.Message}"); | ||
| Console.WriteLine("Diagnostics:"); | ||
| Console.WriteLine(ex.Diagnostics.ToString()); | ||
| } | ||
| long hitCount = tooManyRequestsRule.GetHitCount(); | ||
| Console.WriteLine($"Total 429 responses: {hitCount}"); | ||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -5,6 +5,7 @@ | |||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| import com.azure.cosmos.BridgeInternal; | ||||||||||||||||||||||||||
| import com.azure.cosmos.ConsistencyLevel; | ||||||||||||||||||||||||||
| import com.azure.cosmos.CosmosClientBuilder; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
| import com.azure.cosmos.CosmosClientBuilder; |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The unused imports com.azure.cosmos.rx.TestSuiteBase and org.testng.annotations.Factory should be removed.
| import com.azure.cosmos.rx.TestSuiteBase; | |
| import io.reactivex.subscribers.TestSubscriber; | |
| import org.mockito.MockedStatic; | |
| import org.mockito.Mockito; | |
| import org.mockito.invocation.InvocationOnMock; | |
| import org.testng.annotations.DataProvider; | |
| import org.testng.annotations.Factory; | |
| import io.reactivex.subscribers.TestSubscriber; | |
| import org.mockito.MockedStatic; | |
| import org.mockito.Mockito; | |
| import org.mockito.invocation.InvocationOnMock; | |
| import org.testng.annotations.DataProvider; |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The when static import from Mockito is unused in the visible code (it appears only in the commented-out test). If the commented test is removed, this import should also be removed.
| import static org.mockito.Mockito.when; |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented-out code should be removed rather than left in the codebase. If this test is meant to be implemented later, create a separate issue or TODO comment explaining the intent.
| /*@Test(groups = "unit") | |
| public void ConsistencyWriter_BarrierRetriesExhaustedWith429_Throws408Async() { | |
| int barrierRequestCount = 0; | |
| sessionContainer = Mockito.mock(ISessionContainer.class); | |
| transportClient = Mockito.mock(TransportClient.class); | |
| when(transportClient.invokeStoreAsync( | |
| Mockito.any(Uri.class), | |
| Mockito.any(RxDocumentServiceRequest.class)) | |
| .thenAnswer(i -> i.getArguments()[0])); | |
| }*/ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,6 +17,13 @@ | |
| */ | ||
| public class RequestTimeoutException extends CosmosException { | ||
|
|
||
| /** | ||
| * Instantiates a new Request timeout exception. | ||
| */ | ||
| public RequestTimeoutException(int subStatusCode) { | ||
| this(RMResources.RequestTimeout, null, subStatusCode); | ||
| } | ||
|
Comment on lines
+20
to
+25
|
||
|
|
||
| /** | ||
| * Instantiates a new Request timeout exception. | ||
| */ | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -27,7 +27,6 @@ | |||||||
| import com.azure.cosmos.implementation.Strings; | ||||||||
| import com.azure.cosmos.implementation.Utils; | ||||||||
| import com.azure.cosmos.implementation.apachecommons.collections.ComparatorUtils; | ||||||||
| import com.azure.cosmos.implementation.directconnectivity.rntbd.ClosedClientTransportException; | ||||||||
| import org.slf4j.Logger; | ||||||||
| import org.slf4j.LoggerFactory; | ||||||||
| import reactor.core.Exceptions; | ||||||||
|
|
@@ -46,6 +45,7 @@ | |||||||
| import java.util.Map; | ||||||||
| import java.util.Set; | ||||||||
| import java.util.concurrent.ConcurrentHashMap; | ||||||||
| import java.util.concurrent.atomic.AtomicBoolean; | ||||||||
| import java.util.concurrent.atomic.AtomicInteger; | ||||||||
| import java.util.concurrent.atomic.AtomicLong; | ||||||||
| import java.util.concurrent.atomic.AtomicReference; | ||||||||
|
|
@@ -386,6 +386,7 @@ Mono<StoreResponse> barrierForGlobalStrong(RxDocumentServiceRequest request, Sto | |||||||
|
|
||||||||
| private Mono<Boolean> waitForWriteBarrierAsync(RxDocumentServiceRequest barrierRequest, long selectedGlobalCommittedLsn) { | ||||||||
| AtomicInteger writeBarrierRetryCount = new AtomicInteger(ConsistencyWriter.MAX_NUMBER_OF_WRITE_BARRIER_READ_RETRIES); | ||||||||
| AtomicBoolean lastAttemptWasThrottled = new AtomicBoolean(false); | ||||||||
| AtomicLong maxGlobalCommittedLsnReceived = new AtomicLong(0); | ||||||||
| return Flux.defer(() -> { | ||||||||
| if (barrierRequest.requestContext.timeoutHelper.isElapsed()) { | ||||||||
|
|
@@ -403,8 +404,35 @@ private Mono<Boolean> waitForWriteBarrierAsync(RxDocumentServiceRequest barrierR | |||||||
| false /*forceReadAll*/); | ||||||||
| return storeResultListObs.flatMap( | ||||||||
| responses -> { | ||||||||
| if (responses != null && responses.stream().anyMatch(response -> response.globalCommittedLSN >= selectedGlobalCommittedLsn)) { | ||||||||
| return Mono.just(Boolean.TRUE); | ||||||||
| //if (responses != null && responses.stream().anyMatch(response -> response.globalCommittedLSN >= selectedGlobalCommittedLsn)) { | ||||||||
| // return Mono.just(Boolean.TRUE); | ||||||||
| //} | ||||||||
|
|
||||||||
|
Comment on lines
+407
to
+410
|
||||||||
| //if (responses != null && responses.stream().anyMatch(response -> response.globalCommittedLSN >= selectedGlobalCommittedLsn)) { | |
| // return Mono.just(Boolean.TRUE); | |
| //} |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The condition responses.stream().count() > 0 is redundant. If you're calling allMatch() on an empty stream, it returns true (vacuous truth). Consider using !responses.isEmpty() for clarity and better performance, or rely on the allMatch() predicate alone if an empty response set should not be treated as throttled.
| if (responses.stream().count() > 0 && responses.stream().allMatch(response -> response.getStoreResponse().getStatus() == HttpConstants.StatusCodes.TOO_MANY_REQUESTS)) { | |
| if (!responses.isEmpty() && responses.stream().allMatch(response -> response.getStoreResponse().getStatus() == HttpConstants.StatusCodes.TOO_MANY_REQUESTS)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test file contains syntax errors and uses C# syntax instead of Java:
string databaseNameshould beString databaseNamenew List<FaultInjectionRule>should be Java syntaxconnectionString:,WithConnectionModeDirect())awaitkeyword is C# syntax (Java uses.block()for reactive code)Guid.NewGuid()is C#, should beUUID.randomUUID()Console.WriteLineis C#, should beSystem.out.printlnor loggerThis entire test file needs to be rewritten using proper Java syntax and Reactor patterns.