Skip to content
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
792c909
Fixes to ReadThroughputAsync for databases with no provisioned throug…
NaluTripician Oct 10, 2022
fbd6aee
Merge branch 'master' into users/nalutripician/ReadThroughputAsyncNoP…
NaluTripician Oct 10, 2022
87b3663
fixed failure to ReadReplaceThroughputResponseTests
NaluTripician Oct 10, 2022
92fdeb0
Merge branch 'users/nalutripician/ReadThroughputAsyncNoProvisionedThr…
NaluTripician Oct 10, 2022
f49f8f9
Added Stream Method
NaluTripician Oct 17, 2022
0144e57
Merge branch 'master' into users/nalutripician/ReadThroughputAsyncNoP…
NaluTripician Oct 17, 2022
bfd3cb9
Ran UpdateContract.ps1
NaluTripician Oct 17, 2022
624344a
Encryption implemtation
NaluTripician Oct 17, 2022
939e721
Fixed spelling error
NaluTripician Oct 17, 2022
c9407d9
Update Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabase.cs
NaluTripician Oct 18, 2022
51539b0
Variable name change
NaluTripician Oct 18, 2022
701c975
Update Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs
NaluTripician Oct 19, 2022
72e6df7
Suggested Changes and fixes
NaluTripician Oct 19, 2022
29778f4
Removed manufactured ResponseMessage + nits
NaluTripician Oct 20, 2022
dc5593f
Simplified PR
NaluTripician Oct 21, 2022
2298107
nits
NaluTripician Oct 21, 2022
33f664f
nits
NaluTripician Oct 21, 2022
eafafc1
initial changes TODO: Update tests
NaluTripician Nov 3, 2022
242e6bd
updated tests
NaluTripician Nov 9, 2022
735186c
nits'
NaluTripician Nov 9, 2022
190bf04
Merge branch 'master' into users/nalutripician/HttpTimeoutsThrow503
NaluTripician Nov 9, 2022
409b25d
Ran UpdateContracts.ps1
NaluTripician Nov 9, 2022
38ecc60
Merge branch 'users/nalutripician/HttpTimeoutsThrow503' of https://gi…
NaluTripician Nov 9, 2022
9801ed2
nits + requested changes
NaluTripician Nov 11, 2022
ce3bd91
Delete NuGet.Config
NaluTripician Nov 11, 2022
33d3ed7
Merge branch 'master' into users/nalutripician/HttpTimeoutsThrow503
NaluTripician Nov 11, 2022
a0017d5
Update Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs
NaluTripician Nov 11, 2022
3d78a50
Update Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs
NaluTripician Nov 11, 2022
3383da2
Update Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs
NaluTripician Nov 11, 2022
396e717
Update Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs
NaluTripician Nov 11, 2022
7d6c307
Use Cosmos Exception Factory, Simplified Tests
NaluTripician Nov 11, 2022
9056324
removed unused code
NaluTripician Nov 15, 2022
24e106b
nits: removed unused code
NaluTripician Nov 15, 2022
6d4ae74
removed unused code
NaluTripician Nov 15, 2022
c696c71
Merge branch 'master' into users/nalutripician/HttpTimeoutsThrow503
NaluTripician Nov 16, 2022
a1bba57
Merge branch 'master' into users/nalutripician/HttpTimeoutsThrow503
ealsur Nov 18, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ namespace Microsoft.Azure.Cosmos
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using global::Azure.Core;
using Microsoft.Azure.Cosmos.Resource.CosmosExceptions;
using Microsoft.Azure.Cosmos.Tracing;
using Microsoft.Azure.Cosmos.Tracing.TraceData;
Expand Down Expand Up @@ -296,6 +298,20 @@ private async Task<HttpResponseMessage> SendHttpHelperAsync(
string message =
$"GatewayStoreClient Request Timeout. Start Time UTC:{startDateTimeUtc}; Total Duration:{(DateTime.UtcNow - startDateTimeUtc).TotalMilliseconds} Ms; Request Timeout {requestTimeout.TotalMilliseconds} Ms; Http Client Timeout:{this.httpClient.Timeout.TotalMilliseconds} Ms; Activity id: {System.Diagnostics.Trace.CorrelationManager.ActivityId};";
e.Data.Add("Message", message);

if (timeoutPolicy.ShouldThrow503OnTimeout)
{
throw new CosmosExceptionFactory.CreateServiceUnavailable(
message: message,
headers: new Headers()
{
ActivityId = System.Diagnostics.Trace.CorrelationManager.ActivityId.ToString()
},
innerException: e);

throw new ServiceUnavailableException(message, e, SubStatusCodes.TransportGenerated503);
}

throw;
}

Expand Down
26 changes: 25 additions & 1 deletion Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,45 @@ internal abstract class HttpTimeoutPolicy

public abstract bool ShouldRetryBasedOnResponse(HttpMethod requestHttpMethod, HttpResponseMessage responseMessage);

public virtual bool ShouldThrow503OnTimeout => false;

public static HttpTimeoutPolicy GetTimeoutPolicy(
DocumentServiceRequest documentServiceRequest)
{
//Query Plan Requests
if (documentServiceRequest.ResourceType == ResourceType.Document
&& documentServiceRequest.OperationType == OperationType.QueryPlan)
{
return HttpTimeoutPolicyControlPlaneRetriableHotPath.Instance;
return HttpTimeoutPolicyControlPlaneRetriableHotPath.InstanceShouldThrow503OnTimeout;
}

//Partition Key Requests
if (documentServiceRequest.ResourceType == ResourceType.PartitionKeyRange)
{
return HttpTimeoutPolicyControlPlaneRetriableHotPath.Instance;
}

//Data Plane Read & Write
if (!HttpTimeoutPolicy.IsMetaData(documentServiceRequest))
{
return HttpTimeoutPolicyDefault.InstanceShouldThrow503OnTimeout;
}

//Meta Data Read
if (HttpTimeoutPolicy.IsMetaData(documentServiceRequest) && documentServiceRequest.IsReadOnlyRequest)
{
return HttpTimeoutPolicyDefault.InstanceShouldThrow503OnTimeout;
}

//Default behavior
return HttpTimeoutPolicyDefault.Instance;

static bool IsMetaData(DocumentServiceRequest request)
{
return (request.OperationType != Documents.OperationType.ExecuteJavaScript && request.ResourceType == ResourceType.StoredProcedure) ||
request.ResourceType != ResourceType.Document;

}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,7 @@ public override bool ShouldRetryBasedOnResponse(HttpMethod requestHttpMethod, Ht
{
return false;
}

public override bool ShouldThrow503OnTimeout => true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@ namespace Microsoft.Azure.Cosmos

internal sealed class HttpTimeoutPolicyControlPlaneRetriableHotPath : HttpTimeoutPolicy
{
public static readonly HttpTimeoutPolicy Instance = new HttpTimeoutPolicyControlPlaneRetriableHotPath();
public static readonly HttpTimeoutPolicy Instance = new HttpTimeoutPolicyControlPlaneRetriableHotPath(false);
public static readonly HttpTimeoutPolicy InstanceShouldThrow503OnTimeout = new HttpTimeoutPolicyControlPlaneRetriableHotPath(true);
public bool shouldThrow503OnTimeout;
private static readonly string Name = nameof(HttpTimeoutPolicyControlPlaneRetriableHotPath);

private HttpTimeoutPolicyControlPlaneRetriableHotPath()
private HttpTimeoutPolicyControlPlaneRetriableHotPath(bool shouldThrow503OnTimeout)
{
this.shouldThrow503OnTimeout = shouldThrow503OnTimeout;
}

private readonly IReadOnlyList<(TimeSpan requestTimeout, TimeSpan delayForNextRequest)> TimeoutsAndDelays = new List<(TimeSpan requestTimeout, TimeSpan delayForNextRequest)>()
Expand Down Expand Up @@ -61,5 +64,7 @@ public override bool ShouldRetryBasedOnResponse(HttpMethod requestHttpMethod, Ht

return true;
}

public override bool ShouldThrow503OnTimeout => this.shouldThrow503OnTimeout;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@ namespace Microsoft.Azure.Cosmos

internal sealed class HttpTimeoutPolicyDefault : HttpTimeoutPolicy
{
public static readonly HttpTimeoutPolicy Instance = new HttpTimeoutPolicyDefault();
public static readonly HttpTimeoutPolicy Instance = new HttpTimeoutPolicyDefault(false);
public static readonly HttpTimeoutPolicy InstanceShouldThrow503OnTimeout = new HttpTimeoutPolicyDefault(true);
public bool shouldThrow503OnTimeout;
private static readonly string Name = nameof(HttpTimeoutPolicyDefault);

private HttpTimeoutPolicyDefault()
private HttpTimeoutPolicyDefault(bool shouldThrow503OnTimeout)
{
this.shouldThrow503OnTimeout = shouldThrow503OnTimeout;
}

private readonly IReadOnlyList<(TimeSpan requestTimeout, TimeSpan delayForNextRequest)> TimeoutsAndDelays = new List<(TimeSpan requestTimeout, TimeSpan delayForNextRequest)>()
Expand Down Expand Up @@ -46,5 +49,7 @@ public override bool ShouldRetryBasedOnResponse(HttpMethod requestHttpMethod, Ht
{
return false;
}

public override bool ShouldThrow503OnTimeout => this.shouldThrow503OnTimeout;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,24 @@ internal static CosmosException CreateBadRequestException(
innerException);
}

internal static CosmosException CreateServiceUnavailable(
string message,
Headers headers,
string stackTrace = default,
ITrace trace = default,
Error error = default,
Exception innerException = default)
{
return CosmosExceptionFactory.Create(
HttpStatusCode.ServiceUnavailable,
message,
stackTrace,
headers,
trace,
error,
innerException);
}

internal static CosmosException CreateUnauthorizedException(
string message,
Headers headers,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace Microsoft.Azure.Cosmos.Tests
using System.Collections.Generic;
using Microsoft.Azure.Cosmos.Tracing;
using Microsoft.Azure.Cosmos.Tracing.TraceData;
using FluentAssertions;

[TestClass]
public class CosmosHttpClientCoreTests
Expand Down Expand Up @@ -259,6 +260,113 @@ async Task<HttpResponseMessage> sendFunc(HttpRequestMessage request, Cancellatio
Assert.AreEqual(3, count, "Should retry 3 times");
}

[TestMethod]
public async Task HttpTimeoutThrow503TestAsync()
{
int count = 0;
async Task<HttpResponseMessage> sendFunc(HttpRequestMessage request, CancellationToken cancellationToken)
{
count++;

throw new OperationCanceledException("API with exception");

}

DocumentClientEventSource eventSource = DocumentClientEventSource.Instance;
HttpMessageHandler messageHandler = new MockMessageHandler(sendFunc);
using CosmosHttpClient cosmoshttpClient = MockCosmosUtil.CreateCosmosHttpClient(() => new HttpClient(messageHandler));

//Data plane read
try
{

HttpResponseMessage responseMessage1 = await cosmoshttpClient.SendHttpAsync(() =>
new ValueTask<HttpRequestMessage>(
result: new HttpRequestMessage(HttpMethod.Get, new Uri("http://localhost"))),
resourceType: ResourceType.Document,
timeoutPolicy: HttpTimeoutPolicyDefault.InstanceShouldThrow503OnTimeout,
clientSideRequestStatistics: new ClientSideRequestStatisticsTraceDatum(DateTime.UtcNow, new TraceSummary()),
cancellationToken: default);
}
catch (Exception e)
{
Assert.AreEqual(3, count, "Should retry 3 times");
Assert.IsInstanceOfType(e, typeof(ServiceUnavailableException));
}
count = 0;

//Data plane write
try
{
HttpResponseMessage responseMessage2 = await cosmoshttpClient.SendHttpAsync(() =>
new ValueTask<HttpRequestMessage>(
result: new HttpRequestMessage(HttpMethod.Post, new Uri("http://localhost"))),
resourceType: ResourceType.Document,
timeoutPolicy: HttpTimeoutPolicyDefault.InstanceShouldThrow503OnTimeout,
clientSideRequestStatistics: new ClientSideRequestStatisticsTraceDatum(DateTime.UtcNow, new TraceSummary()),
cancellationToken: default);
}
catch (Exception e)
{
Assert.AreEqual(1, count, "Post methods should not retry");
Assert.IsInstanceOfType(e, typeof(ServiceUnavailableException));
}
count = 0;

//Meta data read
try
{
HttpResponseMessage responseMessage3 = await cosmoshttpClient.SendHttpAsync(() =>
new ValueTask<HttpRequestMessage>(
result: new HttpRequestMessage(HttpMethod.Get, new Uri("http://localhost"))),
resourceType: ResourceType.Database,
timeoutPolicy: HttpTimeoutPolicyControlPlaneRead.Instance,
clientSideRequestStatistics: new ClientSideRequestStatisticsTraceDatum(DateTime.UtcNow, new TraceSummary()),
cancellationToken: default);
}
catch (Exception e)
{
Assert.AreEqual(3, count, "Should retry 3 times");
Assert.IsInstanceOfType(e, typeof(ServiceUnavailableException));
}
count = 0;

//Query plan read (note all query plan operations are reads).
try
{
HttpResponseMessage responseMessage2 = await cosmoshttpClient.SendHttpAsync(() =>
new ValueTask<HttpRequestMessage>(
result: new HttpRequestMessage(HttpMethod.Get, new Uri("http://localhost"))),
resourceType: ResourceType.Document,
timeoutPolicy: HttpTimeoutPolicyControlPlaneRetriableHotPath.InstanceShouldThrow503OnTimeout,
clientSideRequestStatistics: new ClientSideRequestStatisticsTraceDatum(DateTime.UtcNow, new TraceSummary()),
cancellationToken: default);
}
catch (Exception e)
{
Assert.AreEqual(3, count, "Should retry 3 times");
Assert.IsInstanceOfType(e, typeof(ServiceUnavailableException));
}
count = 0;

//Metadata Write (Should throw a 408 OperationCanceledException rather than a 503)
try
{
HttpResponseMessage responseMessage2 = await cosmoshttpClient.SendHttpAsync(() =>
new ValueTask<HttpRequestMessage>(
result: new HttpRequestMessage(HttpMethod.Get, new Uri("http://localhost"))),
resourceType: ResourceType.Database,
timeoutPolicy: HttpTimeoutPolicyDefault.Instance,
clientSideRequestStatistics: new ClientSideRequestStatisticsTraceDatum(DateTime.UtcNow, new TraceSummary()),
cancellationToken: default);
}
catch (Exception e)
{
Assert.AreEqual(3, count, "Post methods should not retry");
Assert.IsInstanceOfType(e, typeof(OperationCanceledException));
}
}

[TestMethod]
public async Task NoRetryOnNoRetryPolicyTestAsync()
{
Expand Down Expand Up @@ -309,7 +417,7 @@ public async Task RetryTransientIssuesForQueryPlanTestAsync()
new Documents.Collections.RequestNameValueCollection());

HttpTimeoutPolicy retryPolicy = HttpTimeoutPolicy.GetTimeoutPolicy(documentServiceRequest);
Assert.AreEqual(HttpTimeoutPolicyControlPlaneRetriableHotPath.Instance, retryPolicy);
Assert.AreEqual(HttpTimeoutPolicyControlPlaneRetriableHotPath.InstanceShouldThrow503OnTimeout, retryPolicy);

int count = 0;
IEnumerator<(TimeSpan requestTimeout, TimeSpan delayForNextRequest)> retry = retryPolicy.GetTimeoutEnumerator();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public async Task DocumentClient_BuildHttpClientFactory_WithHandler()
uri: new Uri("https://localhost"),
additionalHeaders: new RequestNameValueCollection(),
resourceType: ResourceType.Document,
timeoutPolicy: HttpTimeoutPolicyDefault.Instance,
timeoutPolicy: HttpTimeoutPolicyDefault.InstanceShouldThrow503OnTimeout,
clientSideRequestStatistics: new ClientSideRequestStatisticsTraceDatum(DateTime.UtcNow, new TraceSummary()),
cancellationToken: default);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -808,7 +808,7 @@ public async Task GatewayStatsDurationTest()

await cosmosHttpClient.SendHttpAsync(() => new ValueTask<HttpRequestMessage>(new HttpRequestMessage(HttpMethod.Get, "http://someuri.com")),
ResourceType.Document,
HttpTimeoutPolicyDefault.Instance,
HttpTimeoutPolicyDefault.InstanceShouldThrow503OnTimeout,
clientSideRequestStatistics,
CancellationToken.None);

Expand Down