internal BatchResponse( HttpStatusCode statusCode, SubStatusCodes subStatusCode, string errorMessage, double requestCharge, TimeSpan?retryAfter, string activityId, ServerBatchRequest serverRequest, CosmosSerializer serializer) : this(statusCode, subStatusCode, errorMessage, requestCharge, retryAfter, activityId, serverRequest.Operations, serializer) { }
internal static async Task <BatchResponse> PopulateFromContentAsync( ResponseMessage responseMessage, ServerBatchRequest serverRequest, CosmosSerializer serializer) { List <BatchOperationResult> results = new List <BatchOperationResult>(); int resizerInitialCapacity = 81920; if (responseMessage.Content.CanSeek) { resizerInitialCapacity = (int)responseMessage.Content.Length; } Result res = await responseMessage.Content.ReadRecordIOAsync( record => { Result r = BatchOperationResult.ReadOperationResult(record, out BatchOperationResult operationResult); if (r != Result.Success) { return(r); } results.Add(operationResult); return(r); }, resizer : new MemorySpanResizer <byte>(resizerInitialCapacity)); if (res != Result.Success) { return(null); } BatchResponse response = new BatchResponse( responseMessage.StatusCode, responseMessage.Headers.SubStatusCode, responseMessage.ErrorMessage, responseMessage.Headers.RequestCharge, responseMessage.Headers.RetryAfter, responseMessage.Headers.ActivityId, responseMessage.Diagnostics, serverRequest, serializer); response.results = results; return(response); }
private static async Task <TransactionalBatchResponse> PopulateFromContentAsync( Stream content, ResponseMessage responseMessage, ServerBatchRequest serverRequest, CosmosSerializerCore serializer, ITrace trace, bool shouldPromoteOperationStatus) { List <TransactionalBatchOperationResult> results = new List <TransactionalBatchOperationResult>(); // content is ensured to be seekable in caller. int resizerInitialCapacity = (int)content.Length; Result res = await content.ReadRecordIOAsync( (Func <ReadOnlyMemory <byte>, Result>)(record => { Result r = TransactionalBatchOperationResult.ReadOperationResult(record, out TransactionalBatchOperationResult operationResult); if (r != Result.Success) { return(r); } operationResult.Trace = trace; results.Add(operationResult); return(r); }), resizer : new MemorySpanResizer <byte>(resizerInitialCapacity)); if (res != Result.Success) { return(null); } HttpStatusCode responseStatusCode = responseMessage.StatusCode; SubStatusCodes responseSubStatusCode = responseMessage.Headers.SubStatusCode; // Promote the operation error status as the Batch response error status if we have a MultiStatus response // to provide users with status codes they are used to. if ((int)responseMessage.StatusCode == (int)StatusCodes.MultiStatus && shouldPromoteOperationStatus) { foreach (TransactionalBatchOperationResult result in results) { if ((int)result.StatusCode != (int)StatusCodes.FailedDependency && (int)result.StatusCode >= (int)StatusCodes.StartingErrorCode) { responseStatusCode = result.StatusCode; responseSubStatusCode = result.SubStatusCode; break; } } } TransactionalBatchResponse response = new TransactionalBatchResponse( responseStatusCode, responseSubStatusCode, responseMessage.ErrorMessage, responseMessage.Headers, trace, serverRequest.Operations, serializer) { results = results }; return(response); }
internal static async Task <TransactionalBatchResponse> FromResponseMessageAsync( ResponseMessage responseMessage, ServerBatchRequest serverRequest, CosmosSerializerCore serializer, bool shouldPromoteOperationStatus, ITrace trace, CancellationToken cancellationToken) { using (ITrace createResponseTrace = trace.StartChild("Create Trace", TraceComponent.Batch, TraceLevel.Info)) { using (responseMessage) { TransactionalBatchResponse response = null; if (responseMessage.Content != null) { Stream content = responseMessage.Content; // Shouldn't be the case practically, but handle it for safety. if (!responseMessage.Content.CanSeek) { content = new MemoryStream(); await responseMessage.Content.CopyToAsync(content); } if (content.ReadByte() == (int)HybridRowVersion.V1) { content.Position = 0; response = await TransactionalBatchResponse.PopulateFromContentAsync( content, responseMessage, serverRequest, serializer, trace, shouldPromoteOperationStatus); if (response == null) { // Convert any payload read failures as InternalServerError response = new TransactionalBatchResponse( HttpStatusCode.InternalServerError, SubStatusCodes.Unknown, ClientResources.ServerResponseDeserializationFailure, responseMessage.Headers, trace, serverRequest.Operations, serializer); } } } if (response == null) { response = new TransactionalBatchResponse( responseMessage.StatusCode, responseMessage.Headers.SubStatusCode, responseMessage.ErrorMessage, responseMessage.Headers, trace, serverRequest.Operations, serializer); } if (response.results == null || response.results.Count != serverRequest.Operations.Count) { if (responseMessage.IsSuccessStatusCode) { // Server should be guaranteeing number of results equal to operations when // batch request is successful - so fail as InternalServerError if this is not the case. response = new TransactionalBatchResponse( HttpStatusCode.InternalServerError, SubStatusCodes.Unknown, ClientResources.InvalidServerResponse, responseMessage.Headers, trace, serverRequest.Operations, serializer); } // When the overall response status code is TooManyRequests, propagate the RetryAfter into the individual operations. int retryAfterMilliseconds = 0; if ((int)responseMessage.StatusCode == (int)StatusCodes.TooManyRequests) { if (!responseMessage.Headers.TryGetValue(HttpConstants.HttpHeaders.RetryAfterInMilliseconds, out string retryAfter) || retryAfter == null || !int.TryParse(retryAfter, out retryAfterMilliseconds)) { retryAfterMilliseconds = 0; } } response.CreateAndPopulateResults(serverRequest.Operations, trace, retryAfterMilliseconds); } return(response); } } }
internal static async Task <BatchResponse> FromResponseMessageAsync( ResponseMessage responseMessage, ServerBatchRequest serverRequest, CosmosSerializer serializer) { using (responseMessage) { BatchResponse response = null; if (responseMessage.IsSuccessStatusCode && responseMessage.Content != null) { response = await BatchResponse.PopulateFromContentAsync(responseMessage, serverRequest, serializer); if (response == null) { // Convert any payload read failures as InternalServerError response = new BatchResponse( HttpStatusCode.InternalServerError, SubStatusCodes.Unknown, ClientResources.ServerResponseDeserializationFailure, responseMessage.Headers.RequestCharge, responseMessage.Headers.RetryAfter, responseMessage.Headers.ActivityId, serverRequest, serializer); } } else { response = new BatchResponse( responseMessage.StatusCode, responseMessage.Headers.SubStatusCode, responseMessage.ErrorMessage, responseMessage.Headers.RequestCharge, responseMessage.Headers.RetryAfter, responseMessage.Headers.ActivityId, serverRequest, serializer); } if (response.results == null || response.results.Count != serverRequest.Operations.Count) { if (responseMessage.IsSuccessStatusCode) { // Server should be guaranteeing number of results equal to operations when // batch request is successful - so fail as InternalServerError if this is not the case. response = new BatchResponse( HttpStatusCode.InternalServerError, SubStatusCodes.Unknown, ClientResources.InvalidServerResponse, responseMessage.Headers.RequestCharge, responseMessage.Headers.RetryAfter, responseMessage.Headers.ActivityId, serverRequest, serializer); } // When the overall response status code is TooManyRequests, propagate the RetryAfter into the individual operations. int retryAfterMilliseconds = 0; if ((int)responseMessage.StatusCode == (int)StatusCodes.TooManyRequests) { if (!responseMessage.Headers.TryGetValue(HttpConstants.HttpHeaders.RetryAfterInMilliseconds, out string retryAfter) || retryAfter == null || !int.TryParse(retryAfter, out retryAfterMilliseconds)) { retryAfterMilliseconds = 0; } } response.results = new List <BatchOperationResult>(); for (int i = 0; i < serverRequest.Operations.Count; i++) { response.results.Add( new BatchOperationResult(response.StatusCode) { SubStatusCode = response.SubStatusCode, RetryAfter = TimeSpan.FromMilliseconds(retryAfterMilliseconds), }); } } return(response); } }
internal static async Task <TransactionalBatchResponse> FromResponseMessageAsync( ResponseMessage responseMessage, ServerBatchRequest serverRequest, CosmosSerializerCore serializer, bool shouldPromoteOperationStatus, bool shouldPerformDecryption, CancellationToken cancellationToken) { using (responseMessage) { TransactionalBatchResponse response = null; if (responseMessage.Content != null) { Stream content = responseMessage.Content; // Shouldn't be the case practically, but handle it for safety. if (!responseMessage.Content.CanSeek) { content = new MemoryStream(); await responseMessage.Content.CopyToAsync(content); } if (content.ReadByte() == (int)HybridRowVersion.V1) { content.Position = 0; response = await TransactionalBatchResponse.PopulateFromContentAsync( content, responseMessage, serverRequest, serializer, shouldPromoteOperationStatus); if (response == null) { // Convert any payload read failures as InternalServerError response = new TransactionalBatchResponse( HttpStatusCode.InternalServerError, SubStatusCodes.Unknown, ClientResources.ServerResponseDeserializationFailure, responseMessage.Headers.RequestCharge, responseMessage.Headers.RetryAfter, responseMessage.Headers.ActivityId, responseMessage.DiagnosticsContext, serverRequest.Operations, serializer); } } } if (response == null) { response = new TransactionalBatchResponse( responseMessage.StatusCode, responseMessage.Headers.SubStatusCode, responseMessage.ErrorMessage, responseMessage.Headers.RequestCharge, responseMessage.Headers.RetryAfter, responseMessage.Headers.ActivityId, responseMessage.DiagnosticsContext, serverRequest.Operations, serializer); } if (response.results == null || response.results.Count != serverRequest.Operations.Count) { if (responseMessage.IsSuccessStatusCode) { // Server should be guaranteeing number of results equal to operations when // batch request is successful - so fail as InternalServerError if this is not the case. response = new TransactionalBatchResponse( HttpStatusCode.InternalServerError, SubStatusCodes.Unknown, ClientResources.InvalidServerResponse, responseMessage.Headers.RequestCharge, responseMessage.Headers.RetryAfter, responseMessage.Headers.ActivityId, responseMessage.DiagnosticsContext, serverRequest.Operations, serializer); } // When the overall response status code is TooManyRequests, propagate the RetryAfter into the individual operations. int retryAfterMilliseconds = 0; if ((int)responseMessage.StatusCode == (int)StatusCodes.TooManyRequests) { if (!responseMessage.Headers.TryGetValue(HttpConstants.HttpHeaders.RetryAfterInMilliseconds, out string retryAfter) || retryAfter == null || !int.TryParse(retryAfter, out retryAfterMilliseconds)) { retryAfterMilliseconds = 0; } } response.CreateAndPopulateResults(serverRequest.Operations, retryAfterMilliseconds); } else if (shouldPerformDecryption) { for (int index = 0; index < serverRequest.Operations.Count; index++) { ContainerCore containerCore = serverRequest.Operations[index].ContainerCore; TransactionalBatchOperationResult result = response.results[index]; result.ResourceStream = await containerCore.ClientContext.DecryptItemAsync( result.ResourceStream, (DatabaseCore)containerCore.Database, responseMessage.DiagnosticsContext, cancellationToken); } } return(response); } }