From 792c909e37208f125a47c073c4c458ebdbef50c5 Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Mon, 10 Oct 2022 10:42:51 -0400 Subject: [PATCH 01/28] Fixes to ReadThroughputAsync for databases with no provisioned throughput and null as request options --- .../src/Resource/Offer/CosmosOffers.cs | 25 ++++++++++++------- .../CosmosThroughputTests.cs | 18 ++++++++++++- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs index 3ba18187c4..5a7d7e7fb3 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs @@ -30,16 +30,23 @@ internal async Task ReadThroughputAsync( RequestOptions requestOptions, CancellationToken cancellationToken = default) { - (OfferV2 offerV2, double requestCharge) = await this.GetOfferV2Async(targetRID, failIfNotConfigured: true, cancellationToken: cancellationToken); + (OfferV2 offerV2, double requestCharge) = await this.GetOfferV2Async(targetRID, failIfNotConfigured: false, cancellationToken: cancellationToken); - return await this.GetThroughputResponseAsync( - streamPayload: null, - operationType: OperationType.Read, - linkUri: new Uri(offerV2.SelfLink, UriKind.Relative), - resourceType: ResourceType.Offer, - currentRequestCharge: requestCharge, - requestOptions: requestOptions, - cancellationToken: cancellationToken); + if (requestOptions == null && offerV2 == null) + { + return new ThroughputResponse(HttpStatusCode.NoContent, null, null, null, null); + } + else + { + return await this.GetThroughputResponseAsync( + streamPayload: null, + operationType: OperationType.Read, + linkUri: new Uri(offerV2.SelfLink, UriKind.Relative), + resourceType: ResourceType.Offer, + currentRequestCharge: requestCharge, + requestOptions: requestOptions, + cancellationToken: cancellationToken); + } } internal async Task ReadThroughputIfExistsAsync( diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs index cbb6200140..778d2e830d 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs @@ -105,7 +105,7 @@ public async Task ContainerRecreateOfferTestAsync() ThroughputResponse offer = await container.ReadThroughputAsync(requestOptions: null); Assert.AreEqual(offer.RequestCharge, this.requestChargeHandler.TotalRequestCharges); Assert.AreEqual(400, offer.Resource.Throughput); - + this.requestChargeHandler.TotalRequestCharges = 0; ThroughputResponse replaceOffer = await container.ReplaceThroughputAsync(2000); Assert.AreEqual(replaceOffer.RequestCharge, this.requestChargeHandler.TotalRequestCharges); @@ -160,6 +160,22 @@ public async Task ContainerRecreateOfferTestAsync() await db1.DeleteAsync(); } + [TestMethod] + public async Task ReadThroughutNullRequestOptions() + { + Database db1 = await this.cosmosClient.CreateDatabaseAsync( + Guid.NewGuid().ToString(), + throughput: null); + try + { + await db1.ReadThroughputAsync(requestOptions: null); + } + catch + { + await db1.DeleteAsync(); + Assert.Fail(); + } + } private async Task RecreateContainerUsingDifferentClient( string databaseId, string containerId, From 87b36638f94ebc330948d9aa7345a34d5c7f19ab Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Mon, 10 Oct 2022 15:02:36 -0400 Subject: [PATCH 02/28] fixed failure to ReadReplaceThroughputResponseTests --- .../src/Resource/Offer/CosmosOffers.cs | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs index 5a7d7e7fb3..37845dacf2 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs @@ -30,23 +30,26 @@ internal async Task ReadThroughputAsync( RequestOptions requestOptions, CancellationToken cancellationToken = default) { - (OfferV2 offerV2, double requestCharge) = await this.GetOfferV2Async(targetRID, failIfNotConfigured: false, cancellationToken: cancellationToken); - - if (requestOptions == null && offerV2 == null) - { - return new ThroughputResponse(HttpStatusCode.NoContent, null, null, null, null); - } - else + if (requestOptions == null) { - return await this.GetThroughputResponseAsync( - streamPayload: null, - operationType: OperationType.Read, - linkUri: new Uri(offerV2.SelfLink, UriKind.Relative), - resourceType: ResourceType.Offer, - currentRequestCharge: requestCharge, - requestOptions: requestOptions, - cancellationToken: cancellationToken); + (OfferV2 nullOfferV2, _) = await this.GetOfferV2Async(targetRID, failIfNotConfigured: false, cancellationToken: cancellationToken); + if (nullOfferV2 == null) + { + return new ThroughputResponse(HttpStatusCode.NoContent, null, null, null, null); + } } + + (OfferV2 offerV2, double requestCharge) = await this.GetOfferV2Async(targetRID, failIfNotConfigured: true, cancellationToken: cancellationToken); + + return await this.GetThroughputResponseAsync( + streamPayload: null, + operationType: OperationType.Read, + linkUri: new Uri(offerV2.SelfLink, UriKind.Relative), + resourceType: ResourceType.Offer, + currentRequestCharge: requestCharge, + requestOptions: requestOptions, + cancellationToken: cancellationToken); + } internal async Task ReadThroughputIfExistsAsync( From f49f8f9525740fef3d7f37a67e37e5a8d96f900b Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Mon, 17 Oct 2022 13:27:54 -0400 Subject: [PATCH 03/28] Added Stream Method --- .../src/Resource/Database/Database.cs | 14 ++++++++ .../src/Resource/Database/DatabaseCore.cs | 14 ++++++++ .../Resource/Database/DatabaseInlineCore.cs | 10 ++++++ .../src/Resource/Offer/CosmosOffers.cs | 36 ++++++++++++++----- .../CosmosThroughputTests.cs | 25 ++++++++----- 5 files changed, 81 insertions(+), 18 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs index 1040472858..0794dfa61b 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs @@ -109,6 +109,7 @@ public abstract Task DeleteAsync( /// /// /// Null value indicates a database with no throughput provisioned. + /// If requestOptions is set to null on a database with no througput provisioned a 404.0 exception will be thrown /// /// Request Units /// Set throughput on a database @@ -138,6 +139,19 @@ public abstract Task ReadThroughputAsync( RequestOptions requestOptions, CancellationToken cancellationToken = default); + /// + /// Gets database throughput in measurement of request units per second in the Azure Cosmos service. + /// + /// + /// + /// A containing a containing the record of retrieving the provisioned throughput for this database . + /// https://aka.ms/cosmosdb-dot-net-exceptions + /// Request Units + /// Set throughput on a database + public abstract Task ReadThroughputStreamAsync( + RequestOptions requestOptions, + CancellationToken cancellationToken = default); + /// /// Sets throughput provisioned for a database in measurement of request units per second in the Azure Cosmos service. /// diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs index f8bbb95276..f5ab1ec111 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs @@ -93,6 +93,20 @@ public async Task ReadThroughputAsync( cancellationToken: cancellationToken); } + public async Task ReadThroughputStreamAsync( + RequestOptions requestOptions, + ITrace trace, + CancellationToken cancellationToken) + { + string rid = await this.GetRIDAsync(cancellationToken); + CosmosOffers cosmosOffers = new CosmosOffers(this.ClientContext); + return await cosmosOffers.ReadThroughputStreamAsync( + targetRID: rid, + requestOptions: requestOptions, + cancellationToken: cancellationToken, + uri: this.LinkUri); + } + internal override async Task ReadThroughputIfExistsAsync( RequestOptions requestOptions, CancellationToken cancellationToken) diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs index 4b5073289a..9c18cc8512 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs @@ -265,6 +265,16 @@ public override Task ReadThroughputAsync( (response) => new OpenTelemetryResponse(response)); } + public override Task ReadThroughputStreamAsync( + RequestOptions requestOptions, + CancellationToken cancellation = default) + { + return this.ClientContext.OperationHelperAsync( + nameof(ReadThroughputStreamAsync), + requestOptions, + (trace) => base.ReadThroughputStreamAsync(requestOptions, trace, cancellation), + (response) => new OpenTelemetryResponse(response)); + } public override Task ReplaceThroughputAsync( int throughput, RequestOptions requestOptions = null, diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs index 37845dacf2..4ac0ba7c5c 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs @@ -30,15 +30,6 @@ internal async Task ReadThroughputAsync( RequestOptions requestOptions, CancellationToken cancellationToken = default) { - if (requestOptions == null) - { - (OfferV2 nullOfferV2, _) = await this.GetOfferV2Async(targetRID, failIfNotConfigured: false, cancellationToken: cancellationToken); - if (nullOfferV2 == null) - { - return new ThroughputResponse(HttpStatusCode.NoContent, null, null, null, null); - } - } - (OfferV2 offerV2, double requestCharge) = await this.GetOfferV2Async(targetRID, failIfNotConfigured: true, cancellationToken: cancellationToken); return await this.GetThroughputResponseAsync( @@ -52,6 +43,33 @@ internal async Task ReadThroughputAsync( } + internal async Task ReadThroughputStreamAsync( + string targetRID, + RequestOptions requestOptions, + string uri, + CancellationToken cancellationToken = default) + { + (OfferV2 offerV2, double requestCharge) = await this.GetOfferV2Async(targetRID, failIfNotConfigured: false, cancellationToken: cancellationToken); + + string resourceUri = offerV2 != null ? new Uri(offerV2.SelfLink, UriKind.Relative).OriginalString : uri; + + ResponseMessage responseMessage = await this.ClientContext.ProcessResourceOperationStreamAsync( + resourceUri: resourceUri, + resourceType: ResourceType.Offer, + operationType: OperationType.Read, + cosmosContainerCore: null, + feedRange: null, + streamPayload: null, + requestOptions: requestOptions, + requestEnricher: null, + trace: NoOpTrace.Singleton, + cancellationToken: cancellationToken); + + responseMessage.Headers.RequestCharge += requestCharge; + + return responseMessage; + } + internal async Task ReadThroughputIfExistsAsync( string targetRID, RequestOptions requestOptions, diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs index 778d2e830d..fa5bd90740 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs @@ -6,6 +6,7 @@ namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests { using System; using System.Net; + using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -166,15 +167,21 @@ public async Task ReadThroughutNullRequestOptions() Database db1 = await this.cosmosClient.CreateDatabaseAsync( Guid.NewGuid().ToString(), throughput: null); - try - { - await db1.ReadThroughputAsync(requestOptions: null); - } - catch - { - await db1.DeleteAsync(); - Assert.Fail(); - } + + ResponseMessage responseMessage1 = await db1.ReadThroughputStreamAsync(requestOptions: null); + + Assert.IsNotNull(responseMessage1); + Assert.AreEqual(HttpStatusCode.BadRequest, responseMessage1.StatusCode); + + Database db2 = await this.cosmosClient.CreateDatabaseAsync( + Guid.NewGuid().ToString(), + throughput: 400); + + ResponseMessage responseMessage2 = await db2.ReadThroughputStreamAsync(requestOptions: null); + + Assert.IsNotNull(responseMessage2); + Assert.AreEqual(HttpStatusCode.OK, responseMessage2.StatusCode); + } private async Task RecreateContainerUsingDifferentClient( string databaseId, From bfd3cb92469c0c43946de192d33691d0c2de1020 Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Mon, 17 Oct 2022 15:58:49 -0400 Subject: [PATCH 04/28] Ran UpdateContract.ps1 --- .../src/Resource/Database/DatabaseInlineCore.cs | 4 ++-- ...aceWriterBaselineTests.PointOperationsExceptionsAsync.xml | 2 +- .../Microsoft.Azure.Cosmos.Tests/Contracts/DotNetSDKAPI.json | 5 +++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs index 9c18cc8512..f8e2eb463f 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs @@ -266,8 +266,8 @@ public override Task ReadThroughputAsync( } public override Task ReadThroughputStreamAsync( - RequestOptions requestOptions, - CancellationToken cancellation = default) + RequestOptions requestOptions, + CancellationToken cancellation = default) { return this.ClientContext.OperationHelperAsync( nameof(ReadThroughputStreamAsync), diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/BaselineTest/TestBaseline/EndToEndTraceWriterBaselineTests.PointOperationsExceptionsAsync.xml b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/BaselineTest/TestBaseline/EndToEndTraceWriterBaselineTests.PointOperationsExceptionsAsync.xml index dad3787a12..350feaa6a9 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/BaselineTest/TestBaseline/EndToEndTraceWriterBaselineTests.PointOperationsExceptionsAsync.xml +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/BaselineTest/TestBaseline/EndToEndTraceWriterBaselineTests.PointOperationsExceptionsAsync.xml @@ -1563,4 +1563,4 @@ - + \ No newline at end of file diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetSDKAPI.json b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetSDKAPI.json index 4e18b8084b..b67ed3489f 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetSDKAPI.json +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetSDKAPI.json @@ -3622,6 +3622,11 @@ "Attributes": [], "MethodInfo": "System.Threading.Tasks.Task`1[Microsoft.Azure.Cosmos.ResponseMessage] ReadStreamAsync(Microsoft.Azure.Cosmos.RequestOptions, System.Threading.CancellationToken);IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" }, + "System.Threading.Tasks.Task`1[Microsoft.Azure.Cosmos.ResponseMessage] ReadThroughputStreamAsync(Microsoft.Azure.Cosmos.RequestOptions, System.Threading.CancellationToken)": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "System.Threading.Tasks.Task`1[Microsoft.Azure.Cosmos.ResponseMessage] ReadThroughputStreamAsync(Microsoft.Azure.Cosmos.RequestOptions, System.Threading.CancellationToken);IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, "System.Threading.Tasks.Task`1[Microsoft.Azure.Cosmos.ThroughputResponse] ReadThroughputAsync(Microsoft.Azure.Cosmos.RequestOptions, System.Threading.CancellationToken)": { "Type": "Method", "Attributes": [], From 624344a533ed4c1591ebaf1e66c82b16462ecab2 Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Mon, 17 Oct 2022 16:08:35 -0400 Subject: [PATCH 05/28] Encryption implemtation --- .../src/EncryptionDatabase.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabase.cs b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabase.cs index 610fab3f18..b03f96ed40 100644 --- a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabase.cs +++ b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabase.cs @@ -342,6 +342,16 @@ public override Task ReadThroughputAsync( cancellationToken); } +#if SKDPROJECTREF + public override Task ReadThroughoutStreamAsync( + RequestOptions requestOptions, + CancellationToken cancellationToken = default) + { + return this.database.ReadThroughoutStreamAsync( + requestOptions, + cancellationToken); + } +#endif public override Task ReplaceThroughputAsync( ThroughputProperties throughputProperties, RequestOptions requestOptions = null, From 939e721f7f6a9182eb043a32d683dbb14fff18a9 Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Mon, 17 Oct 2022 16:17:05 -0400 Subject: [PATCH 06/28] Fixed spelling error --- Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabase.cs b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabase.cs index b03f96ed40..2ea707c5aa 100644 --- a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabase.cs +++ b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabase.cs @@ -342,7 +342,7 @@ public override Task ReadThroughputAsync( cancellationToken); } -#if SKDPROJECTREF +#if SDKPROJECTREF public override Task ReadThroughoutStreamAsync( RequestOptions requestOptions, CancellationToken cancellationToken = default) From c9407d90385e70d21aed3b68963b69093e47eb4e Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Tue, 18 Oct 2022 10:05:07 -0400 Subject: [PATCH 07/28] Update Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabase.cs Co-authored-by: Matias Quaranta --- Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabase.cs b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabase.cs index 2ea707c5aa..a31146375e 100644 --- a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabase.cs +++ b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabase.cs @@ -343,7 +343,7 @@ public override Task ReadThroughputAsync( } #if SDKPROJECTREF - public override Task ReadThroughoutStreamAsync( + public override Task ReadThroughputStreamAsync( RequestOptions requestOptions, CancellationToken cancellationToken = default) { From 51539b0b0aef0ba9105bb800d8ee42f46fa8f010 Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Tue, 18 Oct 2022 10:15:18 -0400 Subject: [PATCH 08/28] Variable name change --- Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabase.cs b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabase.cs index a31146375e..c913f35a80 100644 --- a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabase.cs +++ b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabase.cs @@ -347,7 +347,7 @@ public override Task ReadThroughputStreamAsync( RequestOptions requestOptions, CancellationToken cancellationToken = default) { - return this.database.ReadThroughoutStreamAsync( + return this.database.ReadThroughputStreamAsync( requestOptions, cancellationToken); } From 701c975f93364fdd5063abfee34d225321761bf5 Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Wed, 19 Oct 2022 09:56:42 -0400 Subject: [PATCH 09/28] Update Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs Co-authored-by: Matias Quaranta --- Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs index 0794dfa61b..a682094df7 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs @@ -145,7 +145,7 @@ public abstract Task ReadThroughputAsync( /// /// /// A containing a containing the record of retrieving the provisioned throughput for this database . - /// https://aka.ms/cosmosdb-dot-net-exceptions + /// https://aka.ms/cosmosdb-dot-net-exceptions#stream-api /// Request Units /// Set throughput on a database public abstract Task ReadThroughputStreamAsync( From 72e6df73f2439fa0a5e60fc80fe8b56d9adc37c0 Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Wed, 19 Oct 2022 12:28:18 -0400 Subject: [PATCH 10/28] Suggested Changes and fixes --- .../src/Resource/Database/Database.cs | 1 - .../src/Resource/Database/DatabaseCore.cs | 24 ++++++--- .../src/Resource/Offer/CosmosOffers.cs | 50 ++++++++++--------- .../CosmosThroughputTests.cs | 25 ++++++---- 4 files changed, 59 insertions(+), 41 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs index a682094df7..aed2c63e0a 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs @@ -109,7 +109,6 @@ public abstract Task DeleteAsync( /// /// /// Null value indicates a database with no throughput provisioned. - /// If requestOptions is set to null on a database with no througput provisioned a 404.0 exception will be thrown /// /// Request Units /// Set throughput on a database diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs index f5ab1ec111..f52dc56469 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs @@ -98,13 +98,23 @@ public async Task ReadThroughputStreamAsync( ITrace trace, CancellationToken cancellationToken) { - string rid = await this.GetRIDAsync(cancellationToken); - CosmosOffers cosmosOffers = new CosmosOffers(this.ClientContext); - return await cosmosOffers.ReadThroughputStreamAsync( - targetRID: rid, - requestOptions: requestOptions, - cancellationToken: cancellationToken, - uri: this.LinkUri); + ResponseMessage responseMessage = await this.ReadStreamAsync(cancellationToken: cancellationToken); + + if (responseMessage.IsSuccessStatusCode) + { + string rid = await this.GetRIDAsync(cancellationToken); + CosmosOffers cosmosOffers = new CosmosOffers(this.ClientContext); + return await cosmosOffers.ReadThroughputStreamAsync( + targetRID: rid, + requestOptions: requestOptions, + cancellationToken: cancellationToken); + } + else + { + return new ResponseMessage( + HttpStatusCode.NotFound, + errorMessage: "Resourse does not exist."); + } } internal override async Task ReadThroughputIfExistsAsync( diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs index 4ac0ba7c5c..0866417eda 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs @@ -12,6 +12,7 @@ namespace Microsoft.Azure.Cosmos using System.Threading.Tasks; using Microsoft.Azure.Cosmos.Handlers; using Microsoft.Azure.Cosmos.Resource.CosmosExceptions; + using Microsoft.Azure.Cosmos.Serialization.HybridRow; using Microsoft.Azure.Cosmos.Tracing; using Microsoft.Azure.Documents; @@ -30,43 +31,44 @@ internal async Task ReadThroughputAsync( RequestOptions requestOptions, CancellationToken cancellationToken = default) { - (OfferV2 offerV2, double requestCharge) = await this.GetOfferV2Async(targetRID, failIfNotConfigured: true, cancellationToken: cancellationToken); + ResponseMessage responseMessage = await this.ReadThroughputStreamAsync(targetRID, requestOptions, cancellationToken); - return await this.GetThroughputResponseAsync( - streamPayload: null, - operationType: OperationType.Read, - linkUri: new Uri(offerV2.SelfLink, UriKind.Relative), - resourceType: ResourceType.Offer, - currentRequestCharge: requestCharge, - requestOptions: requestOptions, - cancellationToken: cancellationToken); - + return this.ClientContext.ResponseFactory.CreateThroughputResponse(responseMessage); } internal async Task ReadThroughputStreamAsync( string targetRID, RequestOptions requestOptions, - string uri, CancellationToken cancellationToken = default) { (OfferV2 offerV2, double requestCharge) = await this.GetOfferV2Async(targetRID, failIfNotConfigured: false, cancellationToken: cancellationToken); - string resourceUri = offerV2 != null ? new Uri(offerV2.SelfLink, UriKind.Relative).OriginalString : uri; + ResponseMessage responseMessage; + if (offerV2 != null) + { + string resourceUri = new Uri(offerV2.SelfLink, UriKind.Relative).OriginalString; - ResponseMessage responseMessage = await this.ClientContext.ProcessResourceOperationStreamAsync( - resourceUri: resourceUri, - resourceType: ResourceType.Offer, - operationType: OperationType.Read, - cosmosContainerCore: null, - feedRange: null, - streamPayload: null, - requestOptions: requestOptions, - requestEnricher: null, - trace: NoOpTrace.Singleton, - cancellationToken: cancellationToken); + responseMessage = await this.ClientContext.ProcessResourceOperationStreamAsync( + resourceUri: resourceUri, + resourceType: ResourceType.Offer, + operationType: OperationType.Read, + cosmosContainerCore: null, + feedRange: null, + streamPayload: null, + requestOptions: requestOptions, + requestEnricher: null, + trace: NoOpTrace.Singleton, + cancellationToken: cancellationToken); + } + else + { + responseMessage = new ResponseMessage( + HttpStatusCode.NotFound, + errorMessage: $"Throughput is not configured for {targetRID}"); + } responseMessage.Headers.RequestCharge += requestCharge; - + return responseMessage; } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs index fa5bd90740..a40d9a0a2f 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs @@ -6,7 +6,6 @@ namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests { using System; using System.Net; - using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -164,25 +163,33 @@ public async Task ContainerRecreateOfferTestAsync() [TestMethod] public async Task ReadThroughutNullRequestOptions() { + //Test for non-existant throughput + ResponseMessage responseMessage1 = await this.cosmosClient.GetDatabase("thisDoesNotExist").ReadThroughputStreamAsync(requestOptions: null); + + Assert.IsNotNull(responseMessage1); + Assert.AreEqual(HttpStatusCode.NotFound, responseMessage1.StatusCode); + + //Test for Database with null provisioned throughput Database db1 = await this.cosmosClient.CreateDatabaseAsync( Guid.NewGuid().ToString(), throughput: null); - ResponseMessage responseMessage1 = await db1.ReadThroughputStreamAsync(requestOptions: null); - - Assert.IsNotNull(responseMessage1); - Assert.AreEqual(HttpStatusCode.BadRequest, responseMessage1.StatusCode); + ResponseMessage responseMessage2 = await db1.ReadThroughputStreamAsync(requestOptions: null); + Assert.IsNotNull(responseMessage2); + Assert.AreEqual(HttpStatusCode.NotFound, responseMessage2.StatusCode); + + //Test for Database with provisioned throughput Database db2 = await this.cosmosClient.CreateDatabaseAsync( Guid.NewGuid().ToString(), throughput: 400); - ResponseMessage responseMessage2 = await db2.ReadThroughputStreamAsync(requestOptions: null); - - Assert.IsNotNull(responseMessage2); - Assert.AreEqual(HttpStatusCode.OK, responseMessage2.StatusCode); + ResponseMessage responseMessage3 = await db2.ReadThroughputStreamAsync(requestOptions: null); + Assert.IsNotNull(responseMessage3); + Assert.AreEqual(HttpStatusCode.OK, responseMessage3.StatusCode); } + private async Task RecreateContainerUsingDifferentClient( string databaseId, string containerId, From 29778f4ce52f65afb6352e34051ee9d09bb8fa3c Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Thu, 20 Oct 2022 16:26:02 -0400 Subject: [PATCH 11/28] Removed manufactured ResponseMessage + nits --- .../src/Resource/Database/DatabaseCore.cs | 4 +-- .../Resource/Database/DatabaseInlineCore.cs | 1 + .../src/Resource/Offer/CosmosOffers.cs | 36 +++++++------------ 3 files changed, 15 insertions(+), 26 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs index f52dc56469..59a9f3eeb8 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs @@ -111,9 +111,7 @@ public async Task ReadThroughputStreamAsync( } else { - return new ResponseMessage( - HttpStatusCode.NotFound, - errorMessage: "Resourse does not exist."); + return responseMessage; } } diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs index f8e2eb463f..c60b4afda9 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs @@ -275,6 +275,7 @@ public override Task ReadThroughputStreamAsync( (trace) => base.ReadThroughputStreamAsync(requestOptions, trace, cancellation), (response) => new OpenTelemetryResponse(response)); } + public override Task ReplaceThroughputAsync( int throughput, RequestOptions requestOptions = null, diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs index 0866417eda..d4b7c96b2e 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs @@ -43,29 +43,19 @@ internal async Task ReadThroughputStreamAsync( { (OfferV2 offerV2, double requestCharge) = await this.GetOfferV2Async(targetRID, failIfNotConfigured: false, cancellationToken: cancellationToken); - ResponseMessage responseMessage; - if (offerV2 != null) - { - string resourceUri = new Uri(offerV2.SelfLink, UriKind.Relative).OriginalString; - - responseMessage = await this.ClientContext.ProcessResourceOperationStreamAsync( - resourceUri: resourceUri, - resourceType: ResourceType.Offer, - operationType: OperationType.Read, - cosmosContainerCore: null, - feedRange: null, - streamPayload: null, - requestOptions: requestOptions, - requestEnricher: null, - trace: NoOpTrace.Singleton, - cancellationToken: cancellationToken); - } - else - { - responseMessage = new ResponseMessage( - HttpStatusCode.NotFound, - errorMessage: $"Throughput is not configured for {targetRID}"); - } + string resourceUri = offerV2 != null ? new Uri(offerV2.SelfLink, UriKind.Relative).OriginalString : String.Empty; + + ResponseMessage responseMessage = await this.ClientContext.ProcessResourceOperationStreamAsync( + resourceUri: resourceUri, + resourceType: ResourceType.Offer, + operationType: OperationType.Read, + cosmosContainerCore: null, + feedRange: null, + streamPayload: null, + requestOptions: requestOptions, + requestEnricher: null, + trace: NoOpTrace.Singleton, + cancellationToken: cancellationToken); responseMessage.Headers.RequestCharge += requestCharge; From dc5593f42ec574443cdd405c0130a011e109205d Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Fri, 21 Oct 2022 13:31:25 -0400 Subject: [PATCH 12/28] Simplified PR --- .../src/EncryptionDatabase.cs | 10 ----- .../src/Resource/Database/Database.cs | 32 +++++++++------- .../src/Resource/Database/DatabaseCore.cs | 22 ----------- .../Resource/Database/DatabaseInlineCore.cs | 11 ------ .../src/Resource/Offer/CosmosOffers.cs | 38 +++++-------------- ...neTests.PointOperationsExceptionsAsync.xml | 2 +- .../CosmosThroughputTests.cs | 30 --------------- .../Contracts/DotNetSDKAPI.json | 5 --- 8 files changed, 28 insertions(+), 122 deletions(-) diff --git a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabase.cs b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabase.cs index c913f35a80..610fab3f18 100644 --- a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabase.cs +++ b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabase.cs @@ -342,16 +342,6 @@ public override Task ReadThroughputAsync( cancellationToken); } -#if SDKPROJECTREF - public override Task ReadThroughputStreamAsync( - RequestOptions requestOptions, - CancellationToken cancellationToken = default) - { - return this.database.ReadThroughputStreamAsync( - requestOptions, - cancellationToken); - } -#endif public override Task ReplaceThroughputAsync( ThroughputProperties throughputProperties, RequestOptions requestOptions = null, diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs index aed2c63e0a..a13f5224a4 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/Database.cs @@ -103,7 +103,24 @@ public abstract Task DeleteAsync( /// The options for the throughput request. /// (Optional) representing request cancellation. /// The throughput response. - /// https://aka.ms/cosmosdb-dot-net-exceptions + /// https://aka.ms/cosmosdb-dot-net-exceptions#typed-api + /// + /// This exception can encapsulate many different types of errors. + /// To determine the specific error always look at the StatusCode property. + /// Some common codes you may get when reading a client encryption key are: + /// + /// + /// StatusCode + /// Reason for exception + /// + /// + /// 404 + /// + /// NotFound - This means the database does not exist or has no throughput assigned. + /// + /// + /// + /// /// /// The provisioned throughput for this database. /// @@ -138,19 +155,6 @@ public abstract Task ReadThroughputAsync( RequestOptions requestOptions, CancellationToken cancellationToken = default); - /// - /// Gets database throughput in measurement of request units per second in the Azure Cosmos service. - /// - /// - /// - /// A containing a containing the record of retrieving the provisioned throughput for this database . - /// https://aka.ms/cosmosdb-dot-net-exceptions#stream-api - /// Request Units - /// Set throughput on a database - public abstract Task ReadThroughputStreamAsync( - RequestOptions requestOptions, - CancellationToken cancellationToken = default); - /// /// Sets throughput provisioned for a database in measurement of request units per second in the Azure Cosmos service. /// diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs index 59a9f3eeb8..f8bbb95276 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs @@ -93,28 +93,6 @@ public async Task ReadThroughputAsync( cancellationToken: cancellationToken); } - public async Task ReadThroughputStreamAsync( - RequestOptions requestOptions, - ITrace trace, - CancellationToken cancellationToken) - { - ResponseMessage responseMessage = await this.ReadStreamAsync(cancellationToken: cancellationToken); - - if (responseMessage.IsSuccessStatusCode) - { - string rid = await this.GetRIDAsync(cancellationToken); - CosmosOffers cosmosOffers = new CosmosOffers(this.ClientContext); - return await cosmosOffers.ReadThroughputStreamAsync( - targetRID: rid, - requestOptions: requestOptions, - cancellationToken: cancellationToken); - } - else - { - return responseMessage; - } - } - internal override async Task ReadThroughputIfExistsAsync( RequestOptions requestOptions, CancellationToken cancellationToken) diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs index c60b4afda9..4b5073289a 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs @@ -265,17 +265,6 @@ public override Task ReadThroughputAsync( (response) => new OpenTelemetryResponse(response)); } - public override Task ReadThroughputStreamAsync( - RequestOptions requestOptions, - CancellationToken cancellation = default) - { - return this.ClientContext.OperationHelperAsync( - nameof(ReadThroughputStreamAsync), - requestOptions, - (trace) => base.ReadThroughputStreamAsync(requestOptions, trace, cancellation), - (response) => new OpenTelemetryResponse(response)); - } - public override Task ReplaceThroughputAsync( int throughput, RequestOptions requestOptions = null, diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs index d4b7c96b2e..612a6f79c3 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs @@ -12,7 +12,6 @@ namespace Microsoft.Azure.Cosmos using System.Threading.Tasks; using Microsoft.Azure.Cosmos.Handlers; using Microsoft.Azure.Cosmos.Resource.CosmosExceptions; - using Microsoft.Azure.Cosmos.Serialization.HybridRow; using Microsoft.Azure.Cosmos.Tracing; using Microsoft.Azure.Documents; @@ -31,35 +30,16 @@ internal async Task ReadThroughputAsync( RequestOptions requestOptions, CancellationToken cancellationToken = default) { - ResponseMessage responseMessage = await this.ReadThroughputStreamAsync(targetRID, requestOptions, cancellationToken); + (OfferV2 offerV2, double requestCharge) = await this.GetOfferV2Async(targetRID, failIfNotConfigured: true, cancellationToken: cancellationToken); - return this.ClientContext.ResponseFactory.CreateThroughputResponse(responseMessage); - } - - internal async Task ReadThroughputStreamAsync( - string targetRID, - RequestOptions requestOptions, - CancellationToken cancellationToken = default) - { - (OfferV2 offerV2, double requestCharge) = await this.GetOfferV2Async(targetRID, failIfNotConfigured: false, cancellationToken: cancellationToken); - - string resourceUri = offerV2 != null ? new Uri(offerV2.SelfLink, UriKind.Relative).OriginalString : String.Empty; - - ResponseMessage responseMessage = await this.ClientContext.ProcessResourceOperationStreamAsync( - resourceUri: resourceUri, - resourceType: ResourceType.Offer, - operationType: OperationType.Read, - cosmosContainerCore: null, - feedRange: null, - streamPayload: null, - requestOptions: requestOptions, - requestEnricher: null, - trace: NoOpTrace.Singleton, - cancellationToken: cancellationToken); - - responseMessage.Headers.RequestCharge += requestCharge; - - return responseMessage; + return await this.GetThroughputResponseAsync( + streamPayload: null, + operationType: OperationType.Read, + linkUri: new Uri(offerV2.SelfLink, UriKind.Relative), + resourceType: ResourceType.Offer, + currentRequestCharge: requestCharge, + requestOptions: requestOptions, + cancellationToken: cancellationToken); } internal async Task ReadThroughputIfExistsAsync( diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/BaselineTest/TestBaseline/EndToEndTraceWriterBaselineTests.PointOperationsExceptionsAsync.xml b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/BaselineTest/TestBaseline/EndToEndTraceWriterBaselineTests.PointOperationsExceptionsAsync.xml index 350feaa6a9..dad3787a12 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/BaselineTest/TestBaseline/EndToEndTraceWriterBaselineTests.PointOperationsExceptionsAsync.xml +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/BaselineTest/TestBaseline/EndToEndTraceWriterBaselineTests.PointOperationsExceptionsAsync.xml @@ -1563,4 +1563,4 @@ - \ No newline at end of file + diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs index a40d9a0a2f..28d5ba4df9 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs @@ -160,36 +160,6 @@ public async Task ContainerRecreateOfferTestAsync() await db1.DeleteAsync(); } - [TestMethod] - public async Task ReadThroughutNullRequestOptions() - { - //Test for non-existant throughput - ResponseMessage responseMessage1 = await this.cosmosClient.GetDatabase("thisDoesNotExist").ReadThroughputStreamAsync(requestOptions: null); - - Assert.IsNotNull(responseMessage1); - Assert.AreEqual(HttpStatusCode.NotFound, responseMessage1.StatusCode); - - //Test for Database with null provisioned throughput - Database db1 = await this.cosmosClient.CreateDatabaseAsync( - Guid.NewGuid().ToString(), - throughput: null); - - ResponseMessage responseMessage2 = await db1.ReadThroughputStreamAsync(requestOptions: null); - - Assert.IsNotNull(responseMessage2); - Assert.AreEqual(HttpStatusCode.NotFound, responseMessage2.StatusCode); - - //Test for Database with provisioned throughput - Database db2 = await this.cosmosClient.CreateDatabaseAsync( - Guid.NewGuid().ToString(), - throughput: 400); - - ResponseMessage responseMessage3 = await db2.ReadThroughputStreamAsync(requestOptions: null); - - Assert.IsNotNull(responseMessage3); - Assert.AreEqual(HttpStatusCode.OK, responseMessage3.StatusCode); - } - private async Task RecreateContainerUsingDifferentClient( string databaseId, string containerId, diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetSDKAPI.json b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetSDKAPI.json index b67ed3489f..4e18b8084b 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetSDKAPI.json +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetSDKAPI.json @@ -3622,11 +3622,6 @@ "Attributes": [], "MethodInfo": "System.Threading.Tasks.Task`1[Microsoft.Azure.Cosmos.ResponseMessage] ReadStreamAsync(Microsoft.Azure.Cosmos.RequestOptions, System.Threading.CancellationToken);IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" }, - "System.Threading.Tasks.Task`1[Microsoft.Azure.Cosmos.ResponseMessage] ReadThroughputStreamAsync(Microsoft.Azure.Cosmos.RequestOptions, System.Threading.CancellationToken)": { - "Type": "Method", - "Attributes": [], - "MethodInfo": "System.Threading.Tasks.Task`1[Microsoft.Azure.Cosmos.ResponseMessage] ReadThroughputStreamAsync(Microsoft.Azure.Cosmos.RequestOptions, System.Threading.CancellationToken);IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" - }, "System.Threading.Tasks.Task`1[Microsoft.Azure.Cosmos.ThroughputResponse] ReadThroughputAsync(Microsoft.Azure.Cosmos.RequestOptions, System.Threading.CancellationToken)": { "Type": "Method", "Attributes": [], From 2298107c4d8c33ced8bb11fb84807d86ee8031bd Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Fri, 21 Oct 2022 13:33:21 -0400 Subject: [PATCH 13/28] nits --- Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs | 2 +- .../CosmosThroughputTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs index 612a6f79c3..bce46250ec 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs @@ -39,7 +39,7 @@ internal async Task ReadThroughputAsync( resourceType: ResourceType.Offer, currentRequestCharge: requestCharge, requestOptions: requestOptions, - cancellationToken: cancellationToken); + cancellationToken: cancellationToken); } internal async Task ReadThroughputIfExistsAsync( diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs index 28d5ba4df9..cbb6200140 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosThroughputTests.cs @@ -105,7 +105,7 @@ public async Task ContainerRecreateOfferTestAsync() ThroughputResponse offer = await container.ReadThroughputAsync(requestOptions: null); Assert.AreEqual(offer.RequestCharge, this.requestChargeHandler.TotalRequestCharges); Assert.AreEqual(400, offer.Resource.Throughput); - + this.requestChargeHandler.TotalRequestCharges = 0; ThroughputResponse replaceOffer = await container.ReplaceThroughputAsync(2000); Assert.AreEqual(replaceOffer.RequestCharge, this.requestChargeHandler.TotalRequestCharges); From 33f664fbf776f3fb483f1468eb534491baa3ce96 Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Fri, 21 Oct 2022 13:34:15 -0400 Subject: [PATCH 14/28] nits --- Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs index bce46250ec..3ba18187c4 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs @@ -39,7 +39,7 @@ internal async Task ReadThroughputAsync( resourceType: ResourceType.Offer, currentRequestCharge: requestCharge, requestOptions: requestOptions, - cancellationToken: cancellationToken); + cancellationToken: cancellationToken); } internal async Task ReadThroughputIfExistsAsync( From eafafc1aca5ef57442c22d3feb212037a41eb70b Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Thu, 3 Nov 2022 16:00:38 -0400 Subject: [PATCH 15/28] initial changes TODO: Update tests --- .../src/HttpClient/CosmosHttpClientCore.cs | 7 ++ .../src/HttpClient/HttpTimeoutPolicy.cs | 32 ++++++- .../HttpTimeoutPolicyControlPlaneRead.cs | 2 + ...meoutPolicyControlPlaneRetriableHotPath.cs | 9 +- .../HttpClient/HttpTimeoutPolicyDefault.cs | 9 +- .../CosmosExceptionFactory.cs | 18 ++++ .../CosmosHttpClientCoreTests.cs | 83 +++++++++++++++++++ 7 files changed, 155 insertions(+), 5 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs b/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs index fa8463e64b..bb7cd693cf 100644 --- a/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs +++ b/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs @@ -10,6 +10,7 @@ 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 Microsoft.Azure.Cosmos.Resource.CosmosExceptions; @@ -296,6 +297,12 @@ private async Task 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 ServiceUnavailableException(message, e, SubStatusCodes.TransportGenerated503); + } + throw; } diff --git a/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs b/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs index 413205cdba..cfe69a13d0 100644 --- a/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs +++ b/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs @@ -18,21 +18,51 @@ 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 + if (!IsMetaData(documentServiceRequest) && documentServiceRequest.IsReadOnlyRequest) + { + return HttpTimeoutPolicyDefault.InstanceShouldThrow503OnTimeout; + } + + //Data Plane Write + if (!IsMetaData(documentServiceRequest) && !documentServiceRequest.IsReadOnlyRequest) + { + return HttpTimeoutPolicyDefault.InstanceShouldThrow503OnTimeout; + } + + //Meta Data Read + + if (IsMetaData(documentServiceRequest) && documentServiceRequest.IsReadOnlyRequest) + { + return HttpTimeoutPolicyDefault.InstanceShouldThrow503OnTimeout; + } + return HttpTimeoutPolicyDefault.Instance; + + static bool IsMetaData(DocumentServiceRequest request) + { + return (request.OperationType != Documents.OperationType.ExecuteJavaScript && request.ResourceType == ResourceType.StoredProcedure) || + request.ResourceType != ResourceType.Document; + + } } } } diff --git a/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicyControlPlaneRead.cs b/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicyControlPlaneRead.cs index 56c55901bb..757134a576 100644 --- a/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicyControlPlaneRead.cs +++ b/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicyControlPlaneRead.cs @@ -44,5 +44,7 @@ public override bool ShouldRetryBasedOnResponse(HttpMethod requestHttpMethod, Ht { return false; } + + public override bool ShouldThrow503OnTimeout => true; } } diff --git a/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicyControlPlaneRetriableHotPath.cs b/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicyControlPlaneRetriableHotPath.cs index c8b8dbfb50..8dbb8a2a44 100644 --- a/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicyControlPlaneRetriableHotPath.cs +++ b/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicyControlPlaneRetriableHotPath.cs @@ -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)>() @@ -61,5 +64,7 @@ public override bool ShouldRetryBasedOnResponse(HttpMethod requestHttpMethod, Ht return true; } + + public override bool ShouldThrow503OnTimeout => this.shouldThrow503OnTimeout; } } diff --git a/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicyDefault.cs b/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicyDefault.cs index 949afc0513..974509c70c 100644 --- a/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicyDefault.cs +++ b/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicyDefault.cs @@ -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)>() @@ -46,5 +49,7 @@ public override bool ShouldRetryBasedOnResponse(HttpMethod requestHttpMethod, Ht { return false; } + + public override bool ShouldThrow503OnTimeout => this.shouldThrow503OnTimeout; } } diff --git a/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosExceptionFactory.cs b/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosExceptionFactory.cs index fff41258b2..547e724cb9 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosExceptionFactory.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosExceptionFactory.cs @@ -211,6 +211,24 @@ internal static CosmosException CreateRequestTimeoutException( innerException); } + internal static CosmosException CreateServiceUnavailableException( + 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 CreateThrottledException( string message, Headers headers, diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs index 00d156e8b7..4dfd760ef9 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs @@ -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 @@ -259,6 +260,88 @@ async Task sendFunc(HttpRequestMessage request, Cancellatio Assert.AreEqual(3, count, "Should retry 3 times"); } + [TestMethod] + public async Task HttpTimeoutThrow503TestAsync() + { + static async Task sendFunc(HttpRequestMessage request, CancellationToken cancellationToken) + { + + 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( + 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.IsInstanceOfType(e, typeof(ServiceUnavailableException)); + } + //Data plane write + + try + { + HttpResponseMessage responseMessage2 = await cosmoshttpClient.SendHttpAsync(() => + new ValueTask( + 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.IsInstanceOfType(e, typeof(ServiceUnavailableException)); + } + + + ////Meta data read + + try + { + HttpResponseMessage responseMessage3 = await cosmoshttpClient.SendHttpAsync(() => + new ValueTask( + 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.IsInstanceOfType(e, typeof(ServiceUnavailableException)); + } + + //Query plan read (note all query plan operations are reads). + try + { + HttpResponseMessage responseMessage2 = await cosmoshttpClient.SendHttpAsync(() => + new ValueTask( + result: new HttpRequestMessage(HttpMethod.Post, new Uri("http://localhost"))), + resourceType: ResourceType.Document, + timeoutPolicy: HttpTimeoutPolicyControlPlaneRetriableHotPath.InstanceShouldThrow503OnTimeout, + clientSideRequestStatistics: new ClientSideRequestStatisticsTraceDatum(DateTime.UtcNow, new TraceSummary()), + cancellationToken: default); + } + catch (Exception e) + { + Assert.IsInstanceOfType(e, typeof(ServiceUnavailableException)); + } + } + [TestMethod] public async Task NoRetryOnNoRetryPolicyTestAsync() { From 242e6bd72e6f2756fa7154db9858041b3d3057fe Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Wed, 9 Nov 2022 10:31:50 -0500 Subject: [PATCH 16/28] updated tests --- .../CosmosExceptions/CosmosExceptionFactory.cs | 18 ------------------ .../CosmosHttpClientCoreTests.cs | 2 +- .../GatewayAccountReaderTests.cs | 2 +- .../GatewayStoreModelTest.cs | 2 +- 4 files changed, 3 insertions(+), 21 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosExceptionFactory.cs b/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosExceptionFactory.cs index 547e724cb9..fff41258b2 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosExceptionFactory.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosExceptionFactory.cs @@ -211,24 +211,6 @@ internal static CosmosException CreateRequestTimeoutException( innerException); } - internal static CosmosException CreateServiceUnavailableException( - 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 CreateThrottledException( string message, Headers headers, diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs index 4dfd760ef9..6e7c567a18 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs @@ -392,7 +392,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(); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayAccountReaderTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayAccountReaderTests.cs index e1cfeb5f40..2fc8359f68 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayAccountReaderTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayAccountReaderTests.cs @@ -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); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs index fe4287484c..43078d1866 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/GatewayStoreModelTest.cs @@ -808,7 +808,7 @@ public async Task GatewayStatsDurationTest() await cosmosHttpClient.SendHttpAsync(() => new ValueTask(new HttpRequestMessage(HttpMethod.Get, "http://someuri.com")), ResourceType.Document, - HttpTimeoutPolicyDefault.Instance, + HttpTimeoutPolicyDefault.InstanceShouldThrow503OnTimeout, clientSideRequestStatistics, CancellationToken.None); From 735186c8ce89dd3fcfbd6f7192f73eb5963a6043 Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Wed, 9 Nov 2022 14:30:55 -0500 Subject: [PATCH 17/28] nits' --- Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs | 2 +- .../Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs b/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs index cfe69a13d0..87cc530f4e 100644 --- a/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs +++ b/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs @@ -49,12 +49,12 @@ public static HttpTimeoutPolicy GetTimeoutPolicy( } //Meta Data Read - if (IsMetaData(documentServiceRequest) && documentServiceRequest.IsReadOnlyRequest) { return HttpTimeoutPolicyDefault.InstanceShouldThrow503OnTimeout; } + //Default behavior return HttpTimeoutPolicyDefault.Instance; static bool IsMetaData(DocumentServiceRequest request) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs index 6e7c567a18..a8b0fed314 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs @@ -290,8 +290,8 @@ static async Task sendFunc(HttpRequestMessage request, Canc { Assert.IsInstanceOfType(e, typeof(ServiceUnavailableException)); } - //Data plane write + //Data plane write try { HttpResponseMessage responseMessage2 = await cosmoshttpClient.SendHttpAsync(() => From 409b25d23c5f4fca0e3508d90e8150d9d52545f8 Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Wed, 9 Nov 2022 16:27:45 -0500 Subject: [PATCH 18/28] Ran UpdateContracts.ps1 --- ...dTraceWriterBaselineTests.PointOperationsExceptionsAsync.xml | 2 +- .../Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/BaselineTest/TestBaseline/EndToEndTraceWriterBaselineTests.PointOperationsExceptionsAsync.xml b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/BaselineTest/TestBaseline/EndToEndTraceWriterBaselineTests.PointOperationsExceptionsAsync.xml index dad3787a12..350feaa6a9 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/BaselineTest/TestBaseline/EndToEndTraceWriterBaselineTests.PointOperationsExceptionsAsync.xml +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/BaselineTest/TestBaseline/EndToEndTraceWriterBaselineTests.PointOperationsExceptionsAsync.xml @@ -1563,4 +1563,4 @@ - + \ No newline at end of file diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs index a8b0fed314..49f2557945 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs @@ -309,7 +309,6 @@ static async Task sendFunc(HttpRequestMessage request, Canc ////Meta data read - try { HttpResponseMessage responseMessage3 = await cosmoshttpClient.SendHttpAsync(() => From 9801ed2704336b86e520a3dc040f1c145a267256 Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Fri, 11 Nov 2022 11:20:56 -0500 Subject: [PATCH 19/28] nits + requested changes --- .../src/HttpClient/CosmosHttpClientCore.cs | 9 +++++ .../src/HttpClient/HttpTimeoutPolicy.cs | 14 +++----- .../CosmosExceptionFactory.cs | 18 ++++++++++ .../CosmosHttpClientCoreTests.cs | 34 ++++++++++++++++--- NuGet.Config | 6 ++++ 5 files changed, 67 insertions(+), 14 deletions(-) create mode 100644 NuGet.Config diff --git a/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs b/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs index bb7cd693cf..d91ee9b820 100644 --- a/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs +++ b/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs @@ -13,6 +13,7 @@ namespace Microsoft.Azure.Cosmos 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; @@ -300,6 +301,14 @@ private async Task SendHttpHelperAsync( if (timeoutPolicy.ShouldThrow503OnTimeout) { + CosmosException serviceUnavailableExcpetion = CosmosExceptionFactory.CreateServiceUnavailable( + message: message, + headers: new Headers() + { + ActivityId = System.Diagnostics.Trace.CorrelationManager.ActivityId.ToString() + }, + innerException: e); + throw new ServiceUnavailableException(message, e, SubStatusCodes.TransportGenerated503); } diff --git a/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs b/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs index 87cc530f4e..5fed0d27cd 100644 --- a/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs +++ b/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs @@ -36,20 +36,14 @@ public static HttpTimeoutPolicy GetTimeoutPolicy( return HttpTimeoutPolicyControlPlaneRetriableHotPath.Instance; } - //Data Plane Read - if (!IsMetaData(documentServiceRequest) && documentServiceRequest.IsReadOnlyRequest) - { - return HttpTimeoutPolicyDefault.InstanceShouldThrow503OnTimeout; - } - - //Data Plane Write - if (!IsMetaData(documentServiceRequest) && !documentServiceRequest.IsReadOnlyRequest) + //Data Plane Read & Write + if (!StaticIsMetaData(documentServiceRequest)) { return HttpTimeoutPolicyDefault.InstanceShouldThrow503OnTimeout; } //Meta Data Read - if (IsMetaData(documentServiceRequest) && documentServiceRequest.IsReadOnlyRequest) + if (StaticIsMetaData(documentServiceRequest) && documentServiceRequest.IsReadOnlyRequest) { return HttpTimeoutPolicyDefault.InstanceShouldThrow503OnTimeout; } @@ -57,7 +51,7 @@ public static HttpTimeoutPolicy GetTimeoutPolicy( //Default behavior return HttpTimeoutPolicyDefault.Instance; - static bool IsMetaData(DocumentServiceRequest request) + static bool StaticIsMetaData(DocumentServiceRequest request) { return (request.OperationType != Documents.OperationType.ExecuteJavaScript && request.ResourceType == ResourceType.StoredProcedure) || request.ResourceType != ResourceType.Document; diff --git a/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosExceptionFactory.cs b/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosExceptionFactory.cs index fff41258b2..b6ae0c0ce4 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosExceptionFactory.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosExceptionFactory.cs @@ -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, diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs index 49f2557945..04cab77151 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs @@ -263,8 +263,10 @@ async Task sendFunc(HttpRequestMessage request, Cancellatio [TestMethod] public async Task HttpTimeoutThrow503TestAsync() { - static async Task sendFunc(HttpRequestMessage request, CancellationToken cancellationToken) + int count = 0; + async Task sendFunc(HttpRequestMessage request, CancellationToken cancellationToken) { + count++; throw new OperationCanceledException("API with exception"); @@ -288,8 +290,10 @@ static async Task sendFunc(HttpRequestMessage request, Canc } catch (Exception e) { + Assert.AreEqual(3, count, "Should retry 3 times"); Assert.IsInstanceOfType(e, typeof(ServiceUnavailableException)); } + count = 0; //Data plane write try @@ -304,11 +308,12 @@ static async Task sendFunc(HttpRequestMessage request, Canc } catch (Exception e) { + Assert.AreEqual(1, count, "Post methods should not retry"); Assert.IsInstanceOfType(e, typeof(ServiceUnavailableException)); } + count = 0; - - ////Meta data read + //Meta data read try { HttpResponseMessage responseMessage3 = await cosmoshttpClient.SendHttpAsync(() => @@ -321,15 +326,17 @@ static async Task sendFunc(HttpRequestMessage request, Canc } 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( - result: new HttpRequestMessage(HttpMethod.Post, new Uri("http://localhost"))), + result: new HttpRequestMessage(HttpMethod.Get, new Uri("http://localhost"))), resourceType: ResourceType.Document, timeoutPolicy: HttpTimeoutPolicyControlPlaneRetriableHotPath.InstanceShouldThrow503OnTimeout, clientSideRequestStatistics: new ClientSideRequestStatisticsTraceDatum(DateTime.UtcNow, new TraceSummary()), @@ -337,8 +344,27 @@ static async Task sendFunc(HttpRequestMessage request, Canc } 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( + 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] diff --git a/NuGet.Config b/NuGet.Config new file mode 100644 index 0000000000..3f0e003403 --- /dev/null +++ b/NuGet.Config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file From ce3bd91c18217d884aa2207ed415bf1d7678b769 Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Fri, 11 Nov 2022 11:21:36 -0500 Subject: [PATCH 20/28] Delete NuGet.Config --- NuGet.Config | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 NuGet.Config diff --git a/NuGet.Config b/NuGet.Config deleted file mode 100644 index 3f0e003403..0000000000 --- a/NuGet.Config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From a0017d581f232744c3b5eaf0066b36f5e71ca43f Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Fri, 11 Nov 2022 12:06:43 -0500 Subject: [PATCH 21/28] Update Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs Co-authored-by: Matias Quaranta --- Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs b/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs index d91ee9b820..30751da611 100644 --- a/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs +++ b/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs @@ -301,7 +301,7 @@ private async Task SendHttpHelperAsync( if (timeoutPolicy.ShouldThrow503OnTimeout) { - CosmosException serviceUnavailableExcpetion = CosmosExceptionFactory.CreateServiceUnavailable( + throw new CosmosExceptionFactory.CreateServiceUnavailable( message: message, headers: new Headers() { From 3d78a504e8acaf180075063245e13e10fe89e7d4 Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Fri, 11 Nov 2022 12:06:59 -0500 Subject: [PATCH 22/28] Update Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs Co-authored-by: Matias Quaranta --- Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs b/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs index 5fed0d27cd..50ee45d81e 100644 --- a/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs +++ b/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs @@ -51,7 +51,7 @@ public static HttpTimeoutPolicy GetTimeoutPolicy( //Default behavior return HttpTimeoutPolicyDefault.Instance; - static bool StaticIsMetaData(DocumentServiceRequest request) + static bool IsMetaData(DocumentServiceRequest request) { return (request.OperationType != Documents.OperationType.ExecuteJavaScript && request.ResourceType == ResourceType.StoredProcedure) || request.ResourceType != ResourceType.Document; From 3383da2ad4bb1d7717771cad9cf059e2f61e929d Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Fri, 11 Nov 2022 12:07:15 -0500 Subject: [PATCH 23/28] Update Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs Co-authored-by: Matias Quaranta --- Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs b/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs index 50ee45d81e..957403ef5a 100644 --- a/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs +++ b/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs @@ -37,7 +37,7 @@ public static HttpTimeoutPolicy GetTimeoutPolicy( } //Data Plane Read & Write - if (!StaticIsMetaData(documentServiceRequest)) + if (!HttpTimeoutPolicy.IsMetaData(documentServiceRequest)) { return HttpTimeoutPolicyDefault.InstanceShouldThrow503OnTimeout; } From 396e71724d5d2023002aa5b0d16b5fef9c13e9f3 Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Fri, 11 Nov 2022 12:07:28 -0500 Subject: [PATCH 24/28] Update Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs Co-authored-by: Matias Quaranta --- Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs b/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs index 957403ef5a..7ce7855677 100644 --- a/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs +++ b/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs @@ -43,7 +43,7 @@ public static HttpTimeoutPolicy GetTimeoutPolicy( } //Meta Data Read - if (StaticIsMetaData(documentServiceRequest) && documentServiceRequest.IsReadOnlyRequest) + if (HttpTimeoutPolicy.IsMetaData(documentServiceRequest) && documentServiceRequest.IsReadOnlyRequest) { return HttpTimeoutPolicyDefault.InstanceShouldThrow503OnTimeout; } From 7d6c3078157a518ecf19d4526d826ce892ed5f4e Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Fri, 11 Nov 2022 15:57:37 -0500 Subject: [PATCH 25/28] Use Cosmos Exception Factory, Simplified Tests --- .../src/HttpClient/CosmosHttpClientCore.cs | 7 +- .../src/HttpClient/HttpTimeoutPolicy.cs | 10 +- .../CosmosExceptionFactory.cs | 2 +- .../CosmosHttpClientCoreTests.cs | 136 +++++++----------- 4 files changed, 57 insertions(+), 98 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs b/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs index 30751da611..c43ef54541 100644 --- a/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs +++ b/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs @@ -301,15 +301,14 @@ private async Task SendHttpHelperAsync( if (timeoutPolicy.ShouldThrow503OnTimeout) { - throw new CosmosExceptionFactory.CreateServiceUnavailable( + throw CosmosExceptionFactory.CreateServiceUnavailableException( message: message, headers: new Headers() { - ActivityId = System.Diagnostics.Trace.CorrelationManager.ActivityId.ToString() + ActivityId = System.Diagnostics.Trace.CorrelationManager.ActivityId.ToString(), + SubStatusCode = SubStatusCodes.TransportGenerated503 }, innerException: e); - - throw new ServiceUnavailableException(message, e, SubStatusCodes.TransportGenerated503); } throw; diff --git a/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs b/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs index 7ce7855677..a3fc51dd91 100644 --- a/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs +++ b/Microsoft.Azure.Cosmos/src/HttpClient/HttpTimeoutPolicy.cs @@ -50,13 +50,13 @@ public static HttpTimeoutPolicy GetTimeoutPolicy( //Default behavior return HttpTimeoutPolicyDefault.Instance; + } - static bool IsMetaData(DocumentServiceRequest request) - { - return (request.OperationType != Documents.OperationType.ExecuteJavaScript && request.ResourceType == ResourceType.StoredProcedure) || - request.ResourceType != ResourceType.Document; + private static bool IsMetaData(DocumentServiceRequest request) + { + return (request.OperationType != Documents.OperationType.ExecuteJavaScript && request.ResourceType == ResourceType.StoredProcedure) || + request.ResourceType != ResourceType.Document; - } } } } diff --git a/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosExceptionFactory.cs b/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosExceptionFactory.cs index b6ae0c0ce4..0648aecbc3 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosExceptionFactory.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosExceptionFactory.cs @@ -283,7 +283,7 @@ internal static CosmosException CreateBadRequestException( innerException); } - internal static CosmosException CreateServiceUnavailable( + internal static CosmosException CreateServiceUnavailableException( string message, Headers headers, string stackTrace = default, diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs index 04cab77151..74c557d127 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs @@ -16,7 +16,8 @@ namespace Microsoft.Azure.Cosmos.Tests using System.Collections.Generic; using Microsoft.Azure.Cosmos.Tracing; using Microsoft.Azure.Cosmos.Tracing.TraceData; - using FluentAssertions; + using System.Drawing.Text; + using System.Security.Policy; [TestClass] public class CosmosHttpClientCoreTests @@ -263,108 +264,67 @@ async Task sendFunc(HttpRequestMessage request, Cancellatio [TestMethod] public async Task HttpTimeoutThrow503TestAsync() { - int count = 0; - async Task sendFunc(HttpRequestMessage request, CancellationToken cancellationToken) + + async Task TestScenarioAsync(HttpMethod method, ResourceType resourceType, HttpTimeoutPolicy timeoutPolicy, Type expectedException, int expectedNumberOfRetrys) { - count++; + int count = 0; + async Task sendFunc(HttpRequestMessage request, CancellationToken cancellationToken) + { + count++; - throw new OperationCanceledException("API with exception"); + throw new OperationCanceledException("API with exception"); - } + } - DocumentClientEventSource eventSource = DocumentClientEventSource.Instance; - HttpMessageHandler messageHandler = new MockMessageHandler(sendFunc); - using CosmosHttpClient cosmoshttpClient = MockCosmosUtil.CreateCosmosHttpClient(() => new HttpClient(messageHandler)); + DocumentClientEventSource eventSource = DocumentClientEventSource.Instance; + HttpMessageHandler messageHandler = new MockMessageHandler(sendFunc); + using CosmosHttpClient cosmoshttpClient = MockCosmosUtil.CreateCosmosHttpClient(() => new HttpClient(messageHandler)); - //Data plane read - try - { + try + { + + HttpResponseMessage responseMessage1 = await cosmoshttpClient.SendHttpAsync(() => + new ValueTask( + result: new HttpRequestMessage(method, new Uri("http://localhost"))), + resourceType: resourceType, + timeoutPolicy: timeoutPolicy, + clientSideRequestStatistics: new ClientSideRequestStatisticsTraceDatum(DateTime.UtcNow, new TraceSummary()), + cancellationToken: default); + } + //catch (CosmosException e) + //{ + // Assert.AreEqual(expectedNumberOfRetrys, count, "Should retry 3 times for read methods, for writes should only be tried once"); + // Assert.AreEqual(e.StatusCode, System.Net.HttpStatusCode.ServiceUnavailable); + //} + catch (Exception e) + { + Assert.AreEqual(expectedNumberOfRetrys, count, "Should retry 3 times for read methods, for writes should only be tried once"); + Assert.AreEqual(e.GetType(), expectedException); + + if (e.GetType() == typeof(CosmosException)) + { + CosmosException cosmosException = (CosmosException)e; + Assert.AreEqual(cosmosException.StatusCode, System.Net.HttpStatusCode.ServiceUnavailable); + Assert.AreEqual((int)cosmosException.SubStatusCode,(int)SubStatusCodes.TransportGenerated503); + } + } - HttpResponseMessage responseMessage1 = await cosmoshttpClient.SendHttpAsync(() => - new ValueTask( - 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 read + await TestScenarioAsync(HttpMethod.Get, ResourceType.Document, HttpTimeoutPolicyDefault.InstanceShouldThrow503OnTimeout, typeof(CosmosException), 3); //Data plane write - try - { - HttpResponseMessage responseMessage2 = await cosmoshttpClient.SendHttpAsync(() => - new ValueTask( - 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; + await TestScenarioAsync(HttpMethod.Post, ResourceType.Document, HttpTimeoutPolicyDefault.InstanceShouldThrow503OnTimeout, typeof(CosmosException), 1); //Meta data read - try - { - HttpResponseMessage responseMessage3 = await cosmoshttpClient.SendHttpAsync(() => - new ValueTask( - 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; + await TestScenarioAsync(HttpMethod.Get, ResourceType.Database, HttpTimeoutPolicyDefault.InstanceShouldThrow503OnTimeout, typeof(CosmosException), 3); //Query plan read (note all query plan operations are reads). - try - { - HttpResponseMessage responseMessage2 = await cosmoshttpClient.SendHttpAsync(() => - new ValueTask( - 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; + await TestScenarioAsync(HttpMethod.Get, ResourceType.Document, HttpTimeoutPolicyDefault.InstanceShouldThrow503OnTimeout, typeof(CosmosException), 3); //Metadata Write (Should throw a 408 OperationCanceledException rather than a 503) - try - { - HttpResponseMessage responseMessage2 = await cosmoshttpClient.SendHttpAsync(() => - new ValueTask( - 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)); - } + await TestScenarioAsync(HttpMethod.Post, ResourceType.Document, HttpTimeoutPolicyDefault.Instance, typeof(TaskCanceledException), 1); } [TestMethod] From 905632472294615305466189342419846a45550a Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Tue, 15 Nov 2022 10:44:24 -0500 Subject: [PATCH 26/28] removed unused code --- .../src/HttpClient/CosmosHttpClientCore.cs | 1 - .../CosmosHttpClientCoreTests.cs | 5 ----- 2 files changed, 6 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs b/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs index c43ef54541..31f365aca7 100644 --- a/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs +++ b/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs @@ -13,7 +13,6 @@ namespace Microsoft.Azure.Cosmos 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; diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs index 74c557d127..e927ca07e0 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs @@ -291,11 +291,6 @@ async Task sendFunc(HttpRequestMessage request, Cancellatio clientSideRequestStatistics: new ClientSideRequestStatisticsTraceDatum(DateTime.UtcNow, new TraceSummary()), cancellationToken: default); } - //catch (CosmosException e) - //{ - // Assert.AreEqual(expectedNumberOfRetrys, count, "Should retry 3 times for read methods, for writes should only be tried once"); - // Assert.AreEqual(e.StatusCode, System.Net.HttpStatusCode.ServiceUnavailable); - //} catch (Exception e) { Assert.AreEqual(expectedNumberOfRetrys, count, "Should retry 3 times for read methods, for writes should only be tried once"); From 24e106b66ed662831ca6e0acd6690c9bc96b7b1c Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Tue, 15 Nov 2022 11:56:19 -0500 Subject: [PATCH 27/28] nits: removed unused code --- .../Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs index e927ca07e0..67c653498b 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosHttpClientCoreTests.cs @@ -16,8 +16,6 @@ namespace Microsoft.Azure.Cosmos.Tests using System.Collections.Generic; using Microsoft.Azure.Cosmos.Tracing; using Microsoft.Azure.Cosmos.Tracing.TraceData; - using System.Drawing.Text; - using System.Security.Policy; [TestClass] public class CosmosHttpClientCoreTests From 6d4ae745d80606094e74484ac058e69c1989e1de Mon Sep 17 00:00:00 2001 From: Nalu Tripician Date: Tue, 15 Nov 2022 11:59:50 -0500 Subject: [PATCH 28/28] removed unused code --- Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs b/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs index 31f365aca7..f86bd6b183 100644 --- a/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs +++ b/Microsoft.Azure.Cosmos/src/HttpClient/CosmosHttpClientCore.cs @@ -10,7 +10,6 @@ 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 Microsoft.Azure.Cosmos.Resource.CosmosExceptions;