Skip to content

Commit 6504c1c

Browse files
committed
Code changes to add new timeout policy for thin client.
1 parent d383d10 commit 6504c1c

9 files changed

Lines changed: 290 additions & 12 deletions

File tree

Microsoft.Azure.Cosmos/src/ClientRetryPolicy.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,11 @@ public void OnBeforeSendRequest(DocumentServiceRequest request)
226226

227227
// Resolve the endpoint for the request and pin the resolution to the resolved endpoint
228228
// This enables marking the endpoint unavailability on endpoint failover/unreachability
229-
this.locationEndpoint = this.globalEndpointManager.ResolveServiceEndpoint(request);
229+
this.locationEndpoint = ConfigurationManager.IsThinClientEnabled(defaultValue: false)
230+
&& !LocationCache.IsMetaData(request)
231+
? this.globalEndpointManager.ResolveThinClientEndpoint(request)
232+
: this.globalEndpointManager.ResolveServiceEndpoint(request);
233+
230234
request.RequestContext.RouteToLocation(this.locationEndpoint);
231235
}
232236

Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ internal abstract class HttpTimeoutPolicy
2121

2222
public static HttpTimeoutPolicy GetTimeoutPolicy(
2323
DocumentServiceRequest documentServiceRequest,
24-
bool isPartitionLevelFailoverEnabled = false)
24+
bool isPartitionLevelFailoverEnabled = false,
25+
bool isThinClientEnabled = false)
2526
{
2627
//Query Plan Requests
2728
if (documentServiceRequest.ResourceType == ResourceType.Document
@@ -43,12 +44,22 @@ public static HttpTimeoutPolicy GetTimeoutPolicy(
4344
return HttpTimeoutPolicyControlPlaneRetriableHotPath.InstanceShouldThrow503OnTimeout;
4445
}
4546

46-
//Data Plane Read
47-
if (!HttpTimeoutPolicy.IsMetaData(documentServiceRequest) && documentServiceRequest.IsReadOnlyRequest)
47+
//Data Plane Operations
48+
if (!HttpTimeoutPolicy.IsMetaData(documentServiceRequest))
4849
{
49-
return isPartitionLevelFailoverEnabled
50-
? HttpTimeoutPolicyForPartitionFailover.InstanceShouldThrow503OnTimeout
51-
: HttpTimeoutPolicyDefault.InstanceShouldThrow503OnTimeout;
50+
if (isThinClientEnabled)
51+
{
52+
return documentServiceRequest.IsReadOnlyRequest
53+
? HttpTimeoutPolicyForThinClient.InstanceShouldRetryAndThrow503OnTimeout
54+
: HttpTimeoutPolicyForThinClient.InstanceShouldNotRetryAndThrow503OnTimeout;
55+
}
56+
// Data Plane Reads.
57+
else if (documentServiceRequest.IsReadOnlyRequest)
58+
{
59+
return isPartitionLevelFailoverEnabled
60+
? HttpTimeoutPolicyForPartitionFailover.InstanceShouldThrow503OnTimeout
61+
: HttpTimeoutPolicyDefault.InstanceShouldThrow503OnTimeout;
62+
}
5263
}
5364

5465
//Meta Data Read
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
//------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All rights reserved.
3+
//------------------------------------------------------------
4+
namespace Microsoft.Azure.Cosmos
5+
{
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Net.Http;
9+
10+
internal sealed class HttpTimeoutPolicyForThinClient : HttpTimeoutPolicy
11+
{
12+
public bool shouldRetry;
13+
public bool shouldThrow503OnTimeout;
14+
private static readonly string Name = nameof(HttpTimeoutPolicyForThinClient);
15+
public static readonly HttpTimeoutPolicy InstanceShouldRetryAndThrow503OnTimeout = new HttpTimeoutPolicyForThinClient(true, true);
16+
public static readonly HttpTimeoutPolicy InstanceShouldNotRetryAndThrow503OnTimeout = new HttpTimeoutPolicyForThinClient(true, false);
17+
18+
private HttpTimeoutPolicyForThinClient(
19+
bool shouldThrow503OnTimeout,
20+
bool shouldRetry)
21+
{
22+
this.shouldThrow503OnTimeout = shouldThrow503OnTimeout;
23+
this.shouldRetry = shouldRetry;
24+
}
25+
26+
private readonly IReadOnlyList<(TimeSpan requestTimeout, TimeSpan delayForNextRequest)> TimeoutsAndDelays = new List<(TimeSpan requestTimeout, TimeSpan delayForNextRequest)>()
27+
{
28+
(TimeSpan.FromSeconds(.5), TimeSpan.Zero),
29+
(TimeSpan.FromSeconds(1), TimeSpan.Zero),
30+
(TimeSpan.FromSeconds(1.5), TimeSpan.Zero),
31+
};
32+
33+
public override string TimeoutPolicyName => HttpTimeoutPolicyForThinClient.Name;
34+
35+
public override int TotalRetryCount => this.TimeoutsAndDelays.Count;
36+
37+
public override IEnumerator<(TimeSpan requestTimeout, TimeSpan delayForNextRequest)> GetTimeoutEnumerator()
38+
{
39+
return this.TimeoutsAndDelays.GetEnumerator();
40+
}
41+
42+
// The hot path should always be safe to retires since it should be retrieving meta data
43+
// information that is not idempotent.
44+
public override bool IsSafeToRetry(HttpMethod httpMethod)
45+
{
46+
return this.shouldRetry;
47+
}
48+
49+
public override bool ShouldRetryBasedOnResponse(HttpMethod requestHttpMethod, HttpResponseMessage responseMessage)
50+
{
51+
if (responseMessage == null)
52+
{
53+
return false;
54+
}
55+
56+
if (responseMessage.StatusCode != System.Net.HttpStatusCode.RequestTimeout)
57+
{
58+
return false;
59+
}
60+
61+
if (!this.IsSafeToRetry(requestHttpMethod))
62+
{
63+
return false;
64+
}
65+
66+
return true;
67+
}
68+
69+
public override bool ShouldThrow503OnTimeout => this.shouldThrow503OnTimeout;
70+
}
71+
}

Microsoft.Azure.Cosmos/src/Routing/GlobalEndpointManager.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ public GlobalEndpointManager(
100100

101101
public ReadOnlyCollection<Uri> WriteEndpoints => this.locationCache.WriteEndpoints;
102102

103+
public ReadOnlyCollection<Uri> ThinClientReadEndpoints => this.locationCache.ThinClientReadEndpoints;
104+
105+
public ReadOnlyCollection<Uri> ThinClientWriteEndpoints => this.locationCache.ThinClientWriteEndpoints;
106+
103107
public int PreferredLocationCount
104108
{
105109
get

Microsoft.Azure.Cosmos/src/Routing/IGlobalEndpointManager.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ internal interface IGlobalEndpointManager : IDisposable
1717

1818
ReadOnlyCollection<Uri> WriteEndpoints { get; }
1919

20+
ReadOnlyCollection<Uri> ThinClientReadEndpoints { get; }
21+
22+
ReadOnlyCollection<Uri> ThinClientWriteEndpoints { get; }
23+
2024
int PreferredLocationCount { get; }
2125

2226
Uri ResolveServiceEndpoint(DocumentServiceRequest request);

Microsoft.Azure.Cosmos/src/Routing/LocationCache.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,16 @@ public ReadOnlyCollection<Uri> WriteEndpoints
124124
return this.locationInfo.WriteEndpoints;
125125
}
126126
}
127+
128+
/// <summary>
129+
/// Gets the list of thin client read endpoints.
130+
/// </summary>
131+
public ReadOnlyCollection<Uri> ThinClientReadEndpoints => this.locationInfo.ThinClientReadEndpoints;
132+
133+
/// <summary>
134+
/// Gets the list of thin client write endpoints.
135+
/// </summary>
136+
public ReadOnlyCollection<Uri> ThinClientWriteEndpoints => this.locationInfo.ThinClientWriteEndpoints;
127137

128138
public ReadOnlyCollection<string> EffectivePreferredLocations => this.locationInfo.EffectivePreferredLocations;
129139

@@ -216,7 +226,7 @@ public void OnLocationPreferenceChanged(ReadOnlyCollection<string> preferredLoca
216226
preferenceList: preferredLocations);
217227
}
218228

219-
public bool IsMetaData(DocumentServiceRequest request)
229+
public static bool IsMetaData(DocumentServiceRequest request)
220230
{
221231
return (request.OperationType != Documents.OperationType.ExecuteJavaScript && request.ResourceType == ResourceType.StoredProcedure) ||
222232
request.ResourceType != ResourceType.Document;
@@ -225,7 +235,7 @@ public bool IsMetaData(DocumentServiceRequest request)
225235
public bool IsMultimasterMetadataWriteRequest(DocumentServiceRequest request)
226236
{
227237
return !request.IsReadOnlyRequest && this.locationInfo.AvailableWriteLocations.Count > 1
228-
&& this.IsMetaData(request)
238+
&& LocationCache.IsMetaData(request)
229239
&& this.CanUseMultipleWriteLocations();
230240

231241
}
@@ -896,6 +906,11 @@ internal bool CanUseMultipleWriteLocations()
896906

897907
internal Uri ResolveThinClientEndpoint(DocumentServiceRequest request, bool isReadRequest)
898908
{
909+
if (request.RequestContext != null && request.RequestContext.LocationEndpointToRoute != null)
910+
{
911+
return request.RequestContext.LocationEndpointToRoute;
912+
}
913+
899914
DatabaseAccountLocationsInfo snapshot = this.locationInfo;
900915
ReadOnlyCollection<Uri> endpoints = isReadRequest
901916
? snapshot.ThinClientReadEndpoints

Microsoft.Azure.Cosmos/src/ThinClientStoreClient.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ private Task<HttpResponseMessage> InvokeClientAsync(
151151
return base.httpClient.SendHttpAsync(
152152
() => this.PrepareRequestForProxyAsync(request, physicalAddress, thinClientEndpoint, globalDatabaseAccountName, clientCollectionCache),
153153
resourceType,
154-
HttpTimeoutPolicy.GetTimeoutPolicy(request),
154+
HttpTimeoutPolicy.GetTimeoutPolicy(request, isThinClientEnabled: true),
155155
request.RequestContext.ClientRequestStatistics,
156156
cancellationToken,
157157
request);

Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/PartitionKeyRangeFailoverTests/MockSetupsHelper.cs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public static void SetupStrongAccountProperties(
3636
accountName,
3737
writeRegions,
3838
readRegions,
39-
shouldEnablePPAF);
39+
shouldEnablePPAF: shouldEnablePPAF);
4040

4141
Uri endpointUri = new Uri(endpoint);
4242
mockHttpClientHandler.Setup(x => x.SendAsync(
@@ -109,6 +109,7 @@ public static HttpResponseMessage CreateStrongAccount(
109109
string accountName,
110110
IList<AccountRegion> writeRegions,
111111
IList<AccountRegion> readRegions,
112+
bool shouldEnableThinClient = false,
112113
bool? shouldEnablePPAF = null)
113114
{
114115
AccountProperties accountProperties = new AccountProperties()
@@ -137,9 +138,29 @@ public static HttpResponseMessage CreateStrongAccount(
137138
AsyncReplication = false,
138139
MinReplicaSetSize = 3,
139140
MaxReplicaSetSize = 4
140-
}
141+
},
141142
};
142143

144+
if (shouldEnableThinClient)
145+
{
146+
accountProperties.AdditionalProperties = new Dictionary<string, JToken>
147+
{
148+
{
149+
"thinClientWritableLocations",
150+
JArray.Parse(@"[
151+
{ 'name': 'East US', 'databaseAccountEndpoint': 'https://thinclientwrite-eastus.documents.azure.com:10650/' }
152+
]")
153+
},
154+
{
155+
"thinClientReadableLocations",
156+
JArray.Parse(@"[
157+
{ 'name': 'East US', 'databaseAccountEndpoint': 'https://thinclientread-eastus.documents.azure.com:10650/' },
158+
{ 'name': 'West US', 'databaseAccountEndpoint': 'https://thinclientread-westus.documents.azure.com:10650/' }
159+
]")
160+
}
161+
};
162+
}
163+
143164
return new HttpResponseMessage()
144165
{
145166
StatusCode = HttpStatusCode.OK,

0 commit comments

Comments
 (0)