Skip to content

Commit 0411701

Browse files
PPAF: Fixes issue where setting RequestTimeout to 0 second will cause PPAF dynamic enablement to break (#5427)
# Pull Request Template ## Description This pull request improves the handling of invalid request timeout values in the Cosmos client and adds a new integration test to verify the behavior. The main focus is ensuring that when a request timeout of 0ms is set, the client falls back to a safe default for hedging thresholds, preventing potential issues with failover strategies. **Partition-level failover and hedging logic improvements:** * Updated `InitializePartitionLevelFailoverWithDefaultHedging` in `DocumentClient.cs` to check if `RequestTimeout` is set to 0ms, and if so, fallback to `DefaultHedgingThresholdInMilliseconds` and log a warning. This prevents invalid timeout values from causing issues with availability strategies. **Testing and validation:** * Added a new test method `ClinetOverrides0msRequestTimeoutValueForPPAF` in `CosmosItemIntegrationTests.cs` to verify that when the client is configured with a 0ms request timeout, the hedging threshold is not set to 0, ensuring the fallback logic works as intended. The test also intercepts gateway responses to simulate specific conditions. ## Type of change Please delete options that are not relevant. - [] Bug fix (non-breaking change which fixes an issue) ## Closing issues To automatically close an issue: closes #5430 --------- Co-authored-by: Debdatta Kunda <[email protected]>
1 parent ce446d2 commit 0411701

File tree

2 files changed

+78
-3
lines changed

2 files changed

+78
-3
lines changed

Microsoft.Azure.Cosmos/src/DocumentClient.cs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6863,9 +6863,20 @@ internal void InitializePartitionLevelFailoverWithDefaultHedging()
68636863
{
68646864
// The default threshold is the minimum value of 1 second and a fraction (currently it's half) of
68656865
// the request timeout value provided by the end customer.
6866-
double defaultThresholdInMillis = Math.Min(
6867-
DocumentClient.DefaultHedgingThresholdInMilliseconds,
6868-
this.ConnectionPolicy.RequestTimeout.TotalMilliseconds / 2);
6866+
double defaultThresholdInMillis;
6867+
6868+
if (this.ConnectionPolicy.RequestTimeout.TotalMilliseconds == 0)
6869+
{
6870+
// If the request timeout is 0, we will use the default hedging theshold value
6871+
defaultThresholdInMillis = DocumentClient.DefaultHedgingThresholdInMilliseconds;
6872+
DefaultTrace.TraceWarning("DocumentClient: Request timeout is set to 0, which is not a valid value. Falling back to default hedging threshold of {0} ms", defaultThresholdInMillis);
6873+
}
6874+
else
6875+
{
6876+
defaultThresholdInMillis = Math.Min(
6877+
DocumentClient.DefaultHedgingThresholdInMilliseconds,
6878+
this.ConnectionPolicy.RequestTimeout.TotalMilliseconds / 2);
6879+
}
68696880

68706881
this.ConnectionPolicy.AvailabilityStrategy = AvailabilityStrategy.SDKDefaultCrossRegionHedgingStrategyForPPAF(
68716882
threshold: TimeSpan.FromMilliseconds(defaultThresholdInMillis),

Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemIntegrationTests.cs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2195,6 +2195,70 @@ public async Task CreateItemAsync_WithThinClientEnabledAndCircuitBreakerEnabledA
21952195
await this.TryDeleteItems(itemsList);
21962196
}
21972197
}
2198+
2199+
[TestMethod]
2200+
[Owner("ntripician")]
2201+
[TestCategory("MultiRegion")]
2202+
[Timeout(70000)]
2203+
public async Task ClinetOverrides0msRequestTimeoutValueForPPAF()
2204+
{
2205+
// Arrange.
2206+
2207+
// Now that the ppaf enablement flag is returned from gateway, we need to intercept the response and remove the flag from the response, so that
2208+
// the environment variable set above is honored.
2209+
HttpClientHandlerHelper httpClientHandlerHelper = new HttpClientHandlerHelper()
2210+
{
2211+
ResponseIntercepter = async (response, request) =>
2212+
{
2213+
string json = await response?.Content?.ReadAsStringAsync();
2214+
if (json.Length > 0 && json.Contains("enablePerPartitionFailoverBehavior"))
2215+
{
2216+
JObject parsedDatabaseAccountResponse = JObject.Parse(json);
2217+
parsedDatabaseAccountResponse.Property("enablePerPartitionFailoverBehavior").Value = "true";
2218+
2219+
HttpResponseMessage interceptedResponse = new()
2220+
{
2221+
StatusCode = response.StatusCode,
2222+
Content = new StringContent(parsedDatabaseAccountResponse.ToString()),
2223+
Version = response.Version,
2224+
ReasonPhrase = response.ReasonPhrase,
2225+
RequestMessage = response.RequestMessage,
2226+
};
2227+
2228+
return interceptedResponse;
2229+
}
2230+
2231+
return response;
2232+
},
2233+
};
2234+
2235+
List<string> preferredRegions = new List<string> { region1, region2, region3 };
2236+
CosmosClientOptions cosmosClientOptions = new CosmosClientOptions()
2237+
{
2238+
ConsistencyLevel = ConsistencyLevel.Session,
2239+
RequestTimeout = TimeSpan.FromSeconds(0),
2240+
ApplicationPreferredRegions = preferredRegions,
2241+
HttpClientFactory = () => new HttpClient(httpClientHandlerHelper),
2242+
};
2243+
2244+
2245+
using CosmosClient cosmosClient = new(connectionString: this.connectionString, clientOptions: cosmosClientOptions);
2246+
Database database = cosmosClient.GetDatabase(MultiRegionSetupHelpers.dbName);
2247+
Container container = database.GetContainer(MultiRegionSetupHelpers.containerName);
2248+
2249+
try
2250+
{
2251+
//request to start document client initiation
2252+
_ = await container.ReadItemAsync<CosmosIntegrationTestObject>("id", new PartitionKey("pk1"));
2253+
}
2254+
catch { }
2255+
2256+
// Act and Assert.
2257+
2258+
CrossRegionHedgingAvailabilityStrategy strat = cosmosClient.DocumentClient.ConnectionPolicy.AvailabilityStrategy as CrossRegionHedgingAvailabilityStrategy;
2259+
Assert.IsNotNull(strat);
2260+
Assert.AreNotEqual(0, strat.Threshold);
2261+
}
21982262

21992263
private async Task TryCreateItems(List<CosmosIntegrationTestObject> testItems)
22002264
{

0 commit comments

Comments
 (0)