public override Task <CosmosResponseMessage> SendAsync(CosmosRequestMessage request, CancellationToken cancellationToken) { if (this.UpdateRequestMessage != null) { this.UpdateRequestMessage(request); } return(base.SendAsync(request, cancellationToken)); }
private static void QueryPlanRequestEnricher( CosmosRequestMessage requestMessage) { requestMessage.Headers.Add(HttpConstants.HttpHeaders.ContentType, RuntimeConstants.MediaTypes.QueryJson); requestMessage.Headers.Add(HttpConstants.HttpHeaders.IsQueryPlanRequest, bool.TrueString); requestMessage.Headers.Add(HttpConstants.HttpHeaders.SupportedQueryFeatures, SupportedQueryFeaturesString); requestMessage.Headers.Add(HttpConstants.HttpHeaders.QueryVersion, new Version(major: 1, minor: 0).ToString()); requestMessage.UseGatewayMode = true; }
public void IsDocumentFeed_ForChangeFeed() { CosmosRequestMessage request = new CosmosRequestMessage(); request.OperationType = OperationType.ReadFeed; request.ResourceType = ResourceType.Document; request.PartitionKeyRangeId = "something"; Assert.IsFalse(request.IsDocumentFeedOperation); }
public override Task <CosmosResponseMessage> SendAsync(CosmosRequestMessage request, CancellationToken cancellationToken) { CosmosResponseMessage httpResponse = null; if (request.Properties.TryGetValue(PreProcessingTestHandler.StatusCodeName, out object statusCodeOut)) { httpResponse = new CosmosResponseMessage((HttpStatusCode)statusCodeOut); } return(Task.FromResult(httpResponse)); }
/// <summary> /// Fill the CosmosRequestMessage headers with the set properties /// </summary> /// <param name="request">The <see cref="CosmosRequestMessage"/></param> public override void FillRequestOptions(CosmosRequestMessage request) { if (this.EnableScriptLogging) { request.Headers.Add(Documents.HttpConstants.HttpHeaders.EnableLogging, bool.TrueString); } RequestOptions.SetSessionToken(request, this.SessionToken); RequestOptions.SetConsistencyLevel(request, this.ConsistencyLevel); base.FillRequestOptions(request); }
public override Task <CosmosResponseMessage> SendAsync( CosmosRequestMessage request, CancellationToken cancellationToken) { CosmosRequestOptions promotedRequestOptions = request.RequestOptions; if (promotedRequestOptions != null) { // Fill request options promotedRequestOptions.FillRequestOptions(request); // Validate the request consistency compatibility with account consistency // Type based access context for requested consistency preferred for performance ConsistencyLevel?consistencyLevel = null; if (promotedRequestOptions is CosmosItemRequestOptions) { consistencyLevel = (promotedRequestOptions as CosmosItemRequestOptions).ConsistencyLevel; } else if (promotedRequestOptions is CosmosQueryRequestOptions) { consistencyLevel = (promotedRequestOptions as CosmosQueryRequestOptions).ConsistencyLevel; } else if (promotedRequestOptions is CosmosStoredProcedureRequestOptions) { consistencyLevel = (promotedRequestOptions as CosmosStoredProcedureRequestOptions).ConsistencyLevel; } if (consistencyLevel.HasValue) { if (!ValidationHelpers.ValidateConsistencyLevel(this.client.AccountConsistencyLevel, consistencyLevel.Value)) { throw new ArgumentException(string.Format( CultureInfo.CurrentUICulture, RMResources.InvalidConsistencyLevel, consistencyLevel.Value.ToString(), this.client.AccountConsistencyLevel)); } } } return(this.client.DocumentClient.EnsureValidClientAsync() .ContinueWith(task => request.AssertPartitioningDetailsAsync(client, cancellationToken)) .ContinueWith(task => { if (task.IsFaulted) { throw task.Exception; } return base.SendAsync(request, cancellationToken); }) .Unwrap()); }
public override async Task <CosmosResponseMessage> SendAsync( CosmosRequestMessage request, CancellationToken cancellationToken) { var response = await base.SendAsync(request, cancellationToken); if (response.StatusCode == System.Net.HttpStatusCode.PreconditionFailed) { response.Headers.Set("x-ms-substatus", "999"); } return(response); }
public void IsDocumentFeed_ForOtherOperations() { CosmosRequestMessage request = new CosmosRequestMessage(); request.OperationType = OperationType.Upsert; request.ResourceType = ResourceType.Document; Assert.IsFalse(request.IsDocumentFeedOperation); CosmosRequestMessage request2 = new CosmosRequestMessage(); request2.OperationType = OperationType.ReadFeed; request2.ResourceType = ResourceType.Database; Assert.IsFalse(request2.IsDocumentFeedOperation); }
public override async Task <CosmosResponseMessage> SendAsync( CosmosRequestMessage request, CancellationToken cancellationToken) { using (Microsoft.ApplicationInsights.Extensibility.IOperationHolder <RequestTelemetry> operation = this.telemetryClient.StartOperation <RequestTelemetry>("CosmosDBRequest")) { this.telemetryClient.TrackTrace($"{request.Method.Method} - {request.RequestUri.ToString()}"); CosmosResponseMessage response = await base.SendAsync(request, cancellationToken); operation.Telemetry.ResponseCode = ((int)response.StatusCode).ToString(); operation.Telemetry.Success = response.IsSuccessStatusCode; this.telemetryClient.StopOperation(operation); return(response); } }
public override Task <CosmosResponseMessage> SendAsync( CosmosRequestMessage request, CancellationToken cancellationToken) { CosmosRequestHandler targetHandler = null; if (request.IsPartitionedFeedOperation) { targetHandler = documentFeedHandler; } else { targetHandler = pointOperationHandler; } return(targetHandler.SendAsync(request, cancellationToken)); }
public override Task <CosmosResponseMessage> SendAsync( CosmosRequestMessage request, CancellationToken cancellationToken) { CosmosRequestHandler targetHandler = null; if (request.OperationType == OperationType.ReadFeed && request.ResourceType == ResourceType.Document) { targetHandler = doucumentFeedHandler; } else { targetHandler = pointOperationHandler; } return(targetHandler.SendAsync(request, cancellationToken)); }
public override async Task <CosmosResponseMessage> SendAsync( CosmosRequestMessage request, CancellationToken cancellationToken) { IDocumentClientRetryPolicy retryPolicyInstance = await this.GetRetryPolicy(request); try { return(await RetryHandler.ExecuteHttpRequestAsync( callbackMethod : () => { return base.SendAsync(request, cancellationToken); }, callShouldRetry : (cosmosResponseMessage, token) => { return retryPolicyInstance.ShouldRetryAsync(cosmosResponseMessage, cancellationToken); }, callShouldRetryException : (exception, token) => { return retryPolicyInstance.ShouldRetryAsync(exception, cancellationToken); }, cancellationToken : cancellationToken)); } catch (DocumentClientException ex) { return(ex.ToCosmosResponseMessage(request)); } catch (AggregateException ex) { // TODO: because the SDK underneath this path uses ContinueWith or task.Result we need to catch AggregateExceptions here // in order to ensure that underlying DocumentClientExceptions get propagated up correctly. Once all ContinueWith and .Result // is removed this catch can be safely removed. AggregateException innerExceptions = ex.Flatten(); Exception docClientException = innerExceptions.InnerExceptions.FirstOrDefault(innerEx => innerEx is DocumentClientException); if (docClientException != null) { return(((DocumentClientException)docClientException).ToCosmosResponseMessage(request)); } throw; } }
public async Task RetryHandlerHttpClientExceptionRefreshesLocations() { DocumentClient dc = new MockDocumentClient(RetryHandlerTests.TestUri, "test"); CosmosClient client = new CosmosClient(new CosmosClientConfiguration(RetryHandlerTests.TestUri.OriginalString, Guid.NewGuid().ToString()), dc); Mock <IDocumentClientRetryPolicy> mockClientRetryPolicy = new Mock <IDocumentClientRetryPolicy>(); mockClientRetryPolicy.Setup(m => m.ShouldRetryAsync(It.IsAny <Exception>(), It.IsAny <CancellationToken>())) .Returns <Exception, CancellationToken>((ex, tooken) => Task.FromResult(ShouldRetryResult.RetryAfter(TimeSpan.FromMilliseconds(1)))); Mock <IRetryPolicyFactory> mockRetryPolicy = new Mock <IRetryPolicyFactory>(); mockRetryPolicy.Setup(m => m.GetRequestPolicy()) .Returns(() => mockClientRetryPolicy.Object); RetryHandler retryHandler = new RetryHandler(mockRetryPolicy.Object); int handlerCalls = 0; int expectedHandlerCalls = 2; TestHandler testHandler = new TestHandler((request, response) => { handlerCalls++; if (handlerCalls == expectedHandlerCalls) { return(TestHandler.ReturnSuccess()); } throw new HttpRequestException("DNS or some other network issue"); }); retryHandler.InnerHandler = testHandler; RequestInvokerHandler invoker = new RequestInvokerHandler(client); invoker.InnerHandler = retryHandler; CosmosRequestMessage requestMessage = new CosmosRequestMessage(HttpMethod.Get, new System.Uri("https://dummy.documents.azure.com:443/dbs")); requestMessage.Headers.Add(HttpConstants.HttpHeaders.PartitionKey, "[]"); requestMessage.ResourceType = ResourceType.Document; requestMessage.OperationType = OperationType.Read; await invoker.SendAsync(requestMessage, new CancellationToken()); Assert.AreEqual(expectedHandlerCalls, handlerCalls); }
public async Task PartitionKeyRangeGoneRetryHandlerOnSuccess() { CosmosClient client = MockDocumentClient.CreateMockCosmosClient(); PartitionKeyRangeGoneRetryHandler retryHandler = new PartitionKeyRangeGoneRetryHandler(client); int handlerCalls = 0; int expectedHandlerCalls = 1; TestHandler testHandler = new TestHandler((request, cancellationToken) => { handlerCalls++; return(TestHandler.ReturnSuccess()); }); retryHandler.InnerHandler = testHandler; RequestInvokerHandler invoker = new RequestInvokerHandler(client); invoker.InnerHandler = retryHandler; CosmosRequestMessage requestMessage = new CosmosRequestMessage(HttpMethod.Get, new Uri("https://dummy.documents.azure.com:443/dbs")); await invoker.SendAsync(requestMessage, new CancellationToken()); Assert.AreEqual(expectedHandlerCalls, handlerCalls); }
public void ValidateSetItemRequestOptions() { CosmosItemRequestOptions options = new CosmosItemRequestOptions(); options.PreTriggers = new List <string>() { "preTrigger" }; options.PostTriggers = new List <string>() { "postTrigger" }; CosmosRequestMessage httpRequest = new CosmosRequestMessage( HttpMethod.Post, new Uri("/dbs/testdb/colls/testcontainer/docs/testId", UriKind.Relative)); options.FillRequestOptions(httpRequest); Assert.IsTrue(httpRequest.Headers.TryGetValue(HttpConstants.HttpHeaders.PreTriggerInclude, out string preTriggerHeader)); Assert.IsTrue(httpRequest.Headers.TryGetValue(HttpConstants.HttpHeaders.PostTriggerInclude, out string postTriggerHeader)); }
public async Task VerifySendUsesOringianlContinuationOnDocumentClientExceptionAfterRetry() { Mock <PartitionRoutingHelper> partitionRoutingHelperMock = this.GetPartitionRoutingHelperMock(); //throw a DocumentClientException partitionRoutingHelperMock.Setup(m => m.TryAddPartitionKeyRangeToContinuationTokenAsync( It.IsAny <INameValueCollection>(), It.IsAny <List <Range <string> > >(), It.IsAny <IRoutingMapProvider>(), It.Is <string>(x => x == CollectionId), It.IsAny <ResolvedRangeInfo>(), It.IsAny <RntbdConstants.RntdbEnumerationDirection>() )).ThrowsAsync(new DocumentClientException("error", HttpStatusCode.ServiceUnavailable, SubStatusCodes.Unknown)); PartitionKeyRangeHandler partitionKeyRangeHandler = new PartitionKeyRangeHandler(MockCosmosUtil.CreateMockCosmosClient(), partitionRoutingHelperMock.Object); TestHandler testHandler = new TestHandler(async(request, cancellationToken) => { CosmosResponseMessage successResponse = await TestHandler.ReturnSuccess(); successResponse.Headers.Remove(HttpConstants.HttpHeaders.Continuation); //Clobber original continuation return(successResponse); }); partitionKeyRangeHandler.InnerHandler = testHandler; //Pass valid collections path because it is required by DocumentServiceRequest's constructor. This can't be mocked because ToDocumentServiceRequest() is an extension method CosmosRequestMessage initialRequest = new CosmosRequestMessage(HttpMethod.Get, new Uri($"{Paths.DatabasesPathSegment}/test/{Paths.CollectionsPathSegment}/test", UriKind.Relative)); initialRequest.OperationType = OperationType.ReadFeed; initialRequest.Headers.Add(HttpConstants.HttpHeaders.Continuation, Continuation); CosmosResponseMessage response = await partitionKeyRangeHandler.SendAsync(initialRequest, CancellationToken.None); Assert.IsFalse(response.IsSuccessStatusCode); Assert.AreEqual(System.Net.HttpStatusCode.ServiceUnavailable, response.StatusCode); //Check if original continuation was restored Assert.AreEqual(Continuation, response.Headers.GetValues(HttpConstants.HttpHeaders.Continuation).First()); Assert.AreEqual(Continuation, initialRequest.Headers.GetValues(HttpConstants.HttpHeaders.Continuation).First()); }
public async Task RequestOptionsHandlerCanHandleRequestOptions() { const string PropertyKey = "propkey"; const string Condition = "*"; object propertyValue = Encoding.UTF8.GetBytes("test"); CosmosRequestOptions options = new CosmosItemRequestOptions { Properties = new Dictionary <string, object>(new List <KeyValuePair <string, object> > { new KeyValuePair <string, object>(PropertyKey, propertyValue) }), AccessCondition = new AccessCondition { Type = AccessConditionType.IfMatch, Condition = Condition } }; TestHandler testHandler = new TestHandler((request, cancellationToken) => { Assert.AreEqual(propertyValue, request.Properties[PropertyKey]); Assert.AreEqual(Condition, request.Headers.GetValues(HttpConstants.HttpHeaders.IfMatch).First()); return(TestHandler.ReturnSuccess()); }); CosmosClient client = MockDocumentClient.CreateMockCosmosClient(); RequestInvokerHandler invoker = new RequestInvokerHandler(client); invoker.InnerHandler = testHandler; CosmosRequestMessage requestMessage = new CosmosRequestMessage(HttpMethod.Get, new System.Uri("https://dummy.documents.azure.com:443/dbs")); requestMessage.Headers.Add(HttpConstants.HttpHeaders.PartitionKey, "[]"); requestMessage.ResourceType = ResourceType.Document; requestMessage.OperationType = OperationType.Read; requestMessage.RequestOptions = options; await invoker.SendAsync(requestMessage, new CancellationToken()); }
internal static CosmosResponseMessage AggregateExceptionConverter(AggregateException aggregateException, CosmosRequestMessage request) { AggregateException innerExceptions = aggregateException.Flatten(); DocumentClientException docClientException = (DocumentClientException)innerExceptions.InnerExceptions.FirstOrDefault(innerEx => innerEx is DocumentClientException); if (docClientException != null) { return(docClientException.ToCosmosResponseMessage(request)); } Exception exception = innerExceptions.InnerExceptions.FirstOrDefault(innerEx => innerEx is CosmosException); CosmosException cosmosException = exception as CosmosException; if (cosmosException != null) { return(new CosmosResponseMessage( headers: cosmosException.Headers, requestMessage: request, errorMessage: cosmosException.Message, statusCode: cosmosException.StatusCode, error: cosmosException.Error)); } return(null); }
internal override async Task <IDocumentClientRetryPolicy> GetRetryPolicyAsync(CosmosRequestMessage request) { return(new InvalidPartitionExceptionRetryPolicy(await client.DocumentClient.GetCollectionCacheAsync(), null)); }
internal abstract Task <IDocumentClientRetryPolicy> GetRetryPolicy(CosmosRequestMessage request);
public override async Task <CosmosResponseMessage> SendAsync( CosmosRequestMessage request, CancellationToken cancellationToken) { CosmosResponseMessage response = null; string originalContinuation = request.Headers.Continuation; try { RntdbEnumerationDirection rntdbEnumerationDirection = RntdbEnumerationDirection.Forward; object direction; if (request.Properties.TryGetValue(HttpConstants.HttpHeaders.EnumerationDirection, out direction)) { rntdbEnumerationDirection = (byte)RntdbEnumerationDirection.Reverse == (byte)direction ? RntdbEnumerationDirection.Reverse : RntdbEnumerationDirection.Forward; } request.Headers.Remove(HttpConstants.HttpHeaders.IsContinuationExpected); request.Headers.Add(HttpConstants.HttpHeaders.IsContinuationExpected, bool.TrueString); object startEpk; object endEpk; if (!request.Properties.TryGetValue(HandlerConstants.StartEpkString, out startEpk)) { startEpk = PartitionKeyInternal.MinimumInclusiveEffectivePartitionKey; } if (!request.Properties.TryGetValue(HandlerConstants.EndEpkString, out endEpk)) { endEpk = PartitionKeyInternal.MaximumExclusiveEffectivePartitionKey; } startEpk = startEpk ?? PartitionKeyInternal.MinimumInclusiveEffectivePartitionKey; endEpk = endEpk ?? PartitionKeyInternal.MaximumExclusiveEffectivePartitionKey; List <Range <string> > providedRanges = new List <Range <string> > { new Range <string>( (string)startEpk, (string)endEpk, isMinInclusive: true, isMaxInclusive: false) }; DocumentServiceRequest serviceRequest = request.ToDocumentServiceRequest(); PartitionKeyRangeCache routingMapProvider = await this.client.DocumentClient.GetPartitionKeyRangeCacheAsync(); CollectionCache collectionCache = await this.client.DocumentClient.GetCollectionCacheAsync(); CosmosContainerSettings collectionFromCache = await collectionCache.ResolveCollectionAsync(serviceRequest, CancellationToken.None); List <CompositeContinuationToken> suppliedTokens; //direction is not expected to change between continuations. Range <string> rangeFromContinuationToken = this.partitionRoutingHelper.ExtractPartitionKeyRangeFromContinuationToken(serviceRequest.Headers, out suppliedTokens); ResolvedRangeInfo resolvedRangeInfo = await this.partitionRoutingHelper.TryGetTargetRangeFromContinuationTokenRange( providedPartitionKeyRanges : providedRanges, routingMapProvider : routingMapProvider, collectionRid : collectionFromCache.ResourceId, rangeFromContinuationToken : rangeFromContinuationToken, suppliedTokens : suppliedTokens, direction : rntdbEnumerationDirection); if (serviceRequest.IsNameBased && resolvedRangeInfo.ResolvedRange == null && resolvedRangeInfo.ContinuationTokens == null) { serviceRequest.ForceNameCacheRefresh = true; collectionFromCache = await collectionCache.ResolveCollectionAsync(serviceRequest, CancellationToken.None); resolvedRangeInfo = await this.partitionRoutingHelper.TryGetTargetRangeFromContinuationTokenRange( providedPartitionKeyRanges : providedRanges, routingMapProvider : routingMapProvider, collectionRid : collectionFromCache.ResourceId, rangeFromContinuationToken : rangeFromContinuationToken, suppliedTokens : suppliedTokens, direction : rntdbEnumerationDirection); } if (resolvedRangeInfo.ResolvedRange == null && resolvedRangeInfo.ContinuationTokens == null) { return(((DocumentClientException) new NotFoundException( $"{DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture)}: Was not able to get queryRoutingInfo even after resolve collection async with force name cache refresh to the following collectionRid: {collectionFromCache.ResourceId} with the supplied tokens: {JsonConvert.SerializeObject(suppliedTokens)}") ).ToCosmosResponseMessage(request)); } serviceRequest.RouteTo(new PartitionKeyRangeIdentity(collectionFromCache.ResourceId, resolvedRangeInfo.ResolvedRange.Id)); response = await base.SendAsync(request, cancellationToken); if (!response.IsSuccessStatusCode) { this.SetOriginalContinuationToken(request, response, originalContinuation); } else { if (!await this.partitionRoutingHelper.TryAddPartitionKeyRangeToContinuationTokenAsync( response.Headers.CosmosMessageHeaders, providedPartitionKeyRanges: providedRanges, routingMapProvider: routingMapProvider, collectionRid: collectionFromCache.ResourceId, resolvedRangeInfo: resolvedRangeInfo, direction: rntdbEnumerationDirection)) { return(((DocumentClientException) new NotFoundException( $"{DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture)}: Call to TryAddPartitionKeyRangeToContinuationTokenAsync failed to the following collectionRid: {collectionFromCache.ResourceId} with the supplied tokens: {JsonConvert.SerializeObject(suppliedTokens)}") ).ToCosmosResponseMessage(request)); } } return(response); } catch (DocumentClientException ex) { CosmosResponseMessage errorResponse = ex.ToCosmosResponseMessage(request); this.SetOriginalContinuationToken(request, errorResponse, originalContinuation); return(errorResponse); } catch (AggregateException ex) { this.SetOriginalContinuationToken(request, response, originalContinuation); // TODO: because the SDK underneath this path uses ContinueWith or task.Result we need to catch AggregateExceptions here // in order to ensure that underlying DocumentClientExceptions get propagated up correctly. Once all ContinueWith and .Result // is removed this catch can be safely removed. AggregateException innerExceptions = ex.Flatten(); Exception docClientException = innerExceptions.InnerExceptions.FirstOrDefault(innerEx => innerEx is DocumentClientException); if (docClientException != null) { return(((DocumentClientException)docClientException).ToCosmosResponseMessage(request)); } throw; } }
internal override async Task <IDocumentClientRetryPolicy> GetRetryPolicyAsync(CosmosRequestMessage request) { return(new PartitionKeyRangeGoneRetryPolicy( await client.DocumentClient.GetCollectionCacheAsync(), await client.DocumentClient.GetPartitionKeyRangeCacheAsync(), PathsHelper.GetCollectionPath(request.RequestUri.ToString()), null)); }