Skip to content

Commit 5bcbbaa

Browse files
committed
Update contracts and fix tests
1 parent 8db9406 commit 5bcbbaa

5 files changed

Lines changed: 81 additions & 19 deletions

File tree

Microsoft.Azure.Cosmos/src/Resource/Settings/ReadConsistencyStrategy.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,8 @@ enum ReadConsistencyStrategy
5151
GlobalStrong = 4,
5252

5353
/// <summary>
54-
/// When set, the SDK automatically adds the hub region processing header so that
55-
/// the backend directs the request to the hub region. Non-hub regions respond with
56-
/// 403/3 (WriteForbidden), which the SDK retries transparently.
54+
/// Returns the latest committed version from the hub (write) region, ensuring reads
55+
/// reflect the most recent writes regardless of which region the client is connected to.
5756
/// </summary>
5857
LastCommittedWriteRegion = 5
5958
}

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ public class CosmosItemTests : BaseCosmosClientHelper
4141
private Container Container = null;
4242
private ContainerProperties containerSettings = null;
4343

44-
private const string HubRegionHeader = "x-ms-cosmos-hub-region-processing-only";
4544
private static readonly string nonPartitionItemId = "fixed-Container-Item";
4645
private static readonly string undefinedPartitionItemId = "undefined-partition-Item";
4746

@@ -4340,7 +4339,7 @@ public async Task ReadItemAsync_ShouldAddHubHeader_OnRetryAfter_404_1002()
43404339

43414340
// Header should NOT be present on first retry (2nd request)
43424341
if (requestCount == 2 &&
4343-
request.Headers.TryGetValues(HubRegionHeader, out IEnumerable<string> firstRetryValues) &&
4342+
request.Headers.TryGetValues(HttpConstants.HttpHeaders.ShouldProcessOnlyInHubRegion, out IEnumerable<string> firstRetryValues) &&
43444343
firstRetryValues.Any())
43454344
{
43464345
Assert.Fail("Header should NOT be present on first retry attempt.");
@@ -4451,7 +4450,7 @@ public async Task ReadItemAsync_WithLastCommittedWriteRegion_RequestLevel_403_3_
44514450
{
44524451
docReadRequestCount++;
44534452

4454-
bool hasHubHeader = request.Headers.TryGetValues(HubRegionHeader, out IEnumerable<string> values)
4453+
bool hasHubHeader = request.Headers.TryGetValues(HttpConstants.HttpHeaders.ShouldProcessOnlyInHubRegion, out IEnumerable<string> values)
44554454
&& values.Any();
44564455
hubHeaderPerRequest.Add(hasHubHeader);
44574456

@@ -4546,7 +4545,7 @@ public async Task ReadItemAsync_WithLastCommittedWriteRegion_ClientLevel_403_3_T
45464545
{
45474546
docReadRequestCount++;
45484547

4549-
bool hasHubHeader = request.Headers.TryGetValues(HubRegionHeader, out IEnumerable<string> values)
4548+
bool hasHubHeader = request.Headers.TryGetValues(HttpConstants.HttpHeaders.ShouldProcessOnlyInHubRegion, out IEnumerable<string> values)
45504549
&& values.Any();
45514550
hubHeaderPerRequest.Add(hasHubHeader);
45524551

@@ -4645,7 +4644,7 @@ public async Task ReadItemAsync_WithNonLastCommittedWriteRegionStrategy_NoHubHea
46454644
{
46464645
interceptedFirstRequest = true;
46474646

4648-
hubHeaderOnFirstRequest = request.Headers.TryGetValues(HubRegionHeader, out IEnumerable<string> values)
4647+
hubHeaderOnFirstRequest = request.Headers.TryGetValues(HttpConstants.HttpHeaders.ShouldProcessOnlyInHubRegion, out IEnumerable<string> values)
46494648
&& values.Any();
46504649

46514650
if (request.Headers.TryGetValues("x-ms-cosmos-read-consistency-strategy", out IEnumerable<string> rcsValues))
@@ -4708,7 +4707,7 @@ public async Task ReadItemAsync_WithoutReadConsistencyStrategy_NoHeaders()
47084707
{
47094708
interceptedFirstRequest = true;
47104709

4711-
hubHeaderOnFirstRequest = request.Headers.TryGetValues(HubRegionHeader, out IEnumerable<string> values)
4710+
hubHeaderOnFirstRequest = request.Headers.TryGetValues(HttpConstants.HttpHeaders.ShouldProcessOnlyInHubRegion, out IEnumerable<string> values)
47124711
&& values.Any();
47134712

47144713
rcsHeaderOnFirstRequest = request.Headers.TryGetValues("x-ms-cosmos-read-consistency-strategy", out IEnumerable<string> rcsValues)

Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ClientRetryPolicyTests.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ public sealed class ClientRetryPolicyTests
2828
private static Uri Location1Endpoint = new Uri("https://location1.documents.azure.com");
2929
private static Uri Location2Endpoint = new Uri("https://location2.documents.azure.com");
3030

31-
private const string HubRegionHeader = "x-ms-cosmos-hub-region-processing-only";
3231
private ReadOnlyCollection<string> preferredLocations;
3332
private AccountProperties databaseAccount;
3433
private GlobalPartitionEndpointManager partitionKeyRangeLocationCache;
@@ -434,7 +433,7 @@ public async Task ClientRetryPolicy_HubRegionHeader_AddedOn404_1002_BasedOnAccou
434433

435434
// First attempt - header should not exist
436435
retryPolicy.OnBeforeSendRequest(request);
437-
Assert.IsNull(request.Headers.GetValues(HubRegionHeader), "Header should not exist on initial request before any 404/1002 error.");
436+
Assert.IsNull(request.Headers.GetValues(HttpConstants.HttpHeaders.ShouldProcessOnlyInHubRegion), "Header should not exist on initial request before any 404/1002 error.");
438437

439438
// Simulate first 404/1002 error
440439
DocumentClientException sessionNotAvailableException = new DocumentClientException(
@@ -450,7 +449,7 @@ public async Task ClientRetryPolicy_HubRegionHeader_AddedOn404_1002_BasedOnAccou
450449

451450
// First retry attempt - header should NOT be present yet
452451
retryPolicy.OnBeforeSendRequest(request);
453-
string[] headerValues = request.Headers.GetValues(HubRegionHeader);
452+
string[] headerValues = request.Headers.GetValues(HttpConstants.HttpHeaders.ShouldProcessOnlyInHubRegion);
454453
Assert.IsNull(headerValues, "Header should NOT be present on first retry attempt (before it fails).");
455454

456455
// Simulate first retry also failing with 404/1002
@@ -498,7 +497,7 @@ public async Task ClientRetryPolicy_HubRegionHeader_AddedOn404_1002_BasedOnAccou
498497
{
499498
// Now verify the header is present on this retry triggered by 503
500499
retryPolicy.OnBeforeSendRequest(request);
501-
headerValues = request.Headers.GetValues(HubRegionHeader);
500+
headerValues = request.Headers.GetValues(HttpConstants.HttpHeaders.ShouldProcessOnlyInHubRegion);
502501
Assert.IsNotNull(headerValues, "Header should be present on retry after 404/1002 flag was set.");
503502
Assert.AreEqual(1, headerValues.Length, "Header should have exactly one value.");
504503
Assert.AreEqual(bool.TrueString, headerValues[0], "Header value should be 'True'.");
@@ -512,7 +511,7 @@ public async Task ClientRetryPolicy_HubRegionHeader_AddedOn404_1002_BasedOnAccou
512511
if (shouldRetry.ShouldRetry)
513512
{
514513
retryPolicy.OnBeforeSendRequest(request);
515-
headerValues = request.Headers.GetValues(HubRegionHeader);
514+
headerValues = request.Headers.GetValues(HttpConstants.HttpHeaders.ShouldProcessOnlyInHubRegion);
516515
Assert.IsNull(headerValues, $"Header should NOT be present on retry attempt {retryAttempt} for multi-master account.");
517516

518517
// Simulate another 404/1002 or 503 to continue retry loop

Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetPreviewSDKAPI.net6.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1491,6 +1491,11 @@
14911491
"Attributes": [],
14921492
"MethodInfo": "Microsoft.Azure.Cosmos.ReadConsistencyStrategy GlobalStrong;IsInitOnly:False;IsStatic:True;"
14931493
},
1494+
"Microsoft.Azure.Cosmos.ReadConsistencyStrategy LastCommittedWriteRegion": {
1495+
"Type": "Field",
1496+
"Attributes": [],
1497+
"MethodInfo": "Microsoft.Azure.Cosmos.ReadConsistencyStrategy LastCommittedWriteRegion;IsInitOnly:False;IsStatic:True;"
1498+
},
14941499
"Microsoft.Azure.Cosmos.ReadConsistencyStrategy LatestCommitted": {
14951500
"Type": "Field",
14961501
"Attributes": [],

Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/HandlerTests.cs

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -875,22 +875,82 @@ public async Task ReadConsistencyStrategyRequestOptionSetsHeaders(string strateg
875875
}
876876

877877
[TestMethod]
878-
public async Task ReadConsistencyStrategyClientLevelApplied()
878+
[DataRow("Query", DisplayName = "Query sets hub header")]
879+
[DataRow("SqlQuery", DisplayName = "SqlQuery sets hub header")]
880+
[DataRow("ReadFeed", DisplayName = "ReadFeed (ChangeFeed) sets hub header")]
881+
public async Task LastCommittedWriteRegionSetsHubHeaderForNonPointReadOperations(string operationTypeName)
882+
{
883+
OperationType operationType = Enum.Parse<OperationType>(operationTypeName);
884+
using CosmosClient client = MockCosmosUtil.CreateMockCosmosClient(accountConsistencyLevel: Cosmos.ConsistencyLevel.Strong);
885+
886+
TestHandler testHandler = new TestHandler((request, cancellationToken) =>
887+
{
888+
Assert.AreEqual(
889+
Cosmos.ReadConsistencyStrategy.LastCommittedWriteRegion.ToString(),
890+
request.Headers[HttpConstants.HttpHeaders.ReadConsistencyStrategy],
891+
"ReadConsistencyStrategy header should be set");
892+
Assert.AreEqual(
893+
bool.TrueString,
894+
request.Headers[HttpConstants.HttpHeaders.ShouldProcessOnlyInHubRegion],
895+
$"Hub region header should be set for LastCommittedWriteRegion on {operationTypeName}");
896+
897+
return TestHandler.ReturnSuccess();
898+
});
899+
900+
RequestInvokerHandler invoker = new RequestInvokerHandler(
901+
client,
902+
requestedClientConsistencyLevel: null,
903+
requestedClientReadConsistencyStrategy: null,
904+
requestedClientPriorityLevel: null,
905+
requestedClientThroughputBucket: null)
906+
{
907+
InnerHandler = testHandler
908+
};
909+
910+
RequestMessage requestMessage = new RequestMessage(HttpMethod.Get, new System.Uri("https://dummy.documents.azure.com:443/dbs"))
911+
{
912+
ResourceType = ResourceType.Document
913+
};
914+
requestMessage.Headers.Add(HttpConstants.HttpHeaders.PartitionKey, "[]");
915+
requestMessage.OperationType = operationType;
916+
requestMessage.RequestOptions = new ItemRequestOptions
917+
{
918+
ReadConsistencyStrategy = Cosmos.ReadConsistencyStrategy.LastCommittedWriteRegion
919+
};
920+
921+
await invoker.SendAsync(requestMessage, new CancellationToken());
922+
}
923+
924+
[TestMethod]
925+
[DataRow("LatestCommitted")]
926+
[DataRow("LastCommittedWriteRegion")]
927+
public async Task ReadConsistencyStrategyClientLevelApplied(string strategyName)
879928
{
880929
// Verify client-level ReadConsistencyStrategy is applied when no request-level is set.
930+
Cosmos.ReadConsistencyStrategy strategy = Enum.Parse<Cosmos.ReadConsistencyStrategy>(strategyName);
881931
using CosmosClient client = MockCosmosUtil.CreateMockCosmosClient(
882932
accountConsistencyLevel: Cosmos.ConsistencyLevel.Strong,
883-
customizeClientBuilder: builder => builder.WithReadConsistencyStrategy(Cosmos.ReadConsistencyStrategy.LastCommittedWriteRegion));
933+
customizeClientBuilder: builder => builder.WithReadConsistencyStrategy(strategy));
884934

885935
TestHandler testHandler = new TestHandler((request, cancellationToken) =>
886936
{
887937
Assert.AreEqual(
888-
Cosmos.ReadConsistencyStrategy.LastCommittedWriteRegion.ToString(),
938+
strategy.ToString(),
889939
request.Headers[HttpConstants.HttpHeaders.ReadConsistencyStrategy]);
890940
Assert.IsNull(request.Headers[HttpConstants.HttpHeaders.ConsistencyLevel],
891941
"ConsistencyLevel header should not be set when ReadConsistencyStrategy is used");
892-
Assert.AreEqual(bool.TrueString, request.Headers[HttpConstants.HttpHeaders.ShouldProcessOnlyInHubRegion],
893-
"Hub region header should be set when client-level LastCommittedWriteRegion is used on a read");
942+
943+
if (strategy == Cosmos.ReadConsistencyStrategy.LastCommittedWriteRegion)
944+
{
945+
Assert.AreEqual(bool.TrueString, request.Headers[HttpConstants.HttpHeaders.ShouldProcessOnlyInHubRegion],
946+
"Hub region header should be set when client-level LastCommittedWriteRegion is used on a read");
947+
}
948+
else
949+
{
950+
Assert.IsNull(request.Headers[HttpConstants.HttpHeaders.ShouldProcessOnlyInHubRegion],
951+
$"Hub region header should NOT be set for {strategyName} strategy");
952+
}
953+
894954
return TestHandler.ReturnSuccess();
895955
});
896956

0 commit comments

Comments
 (0)