diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseDmlNode.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseDmlNode.cs index 5d1a5562..64effc68 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseDmlNode.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseDmlNode.cs @@ -807,7 +807,7 @@ private async Task ExecuteSingleRequest(OrganizationRequest req, Operation { Interlocked.Increment(ref _inProgressCount); - for (var retry = 0; ; retry++) + for (var retry = 0; !options.CancellationToken.IsCancellationRequested; retry++) { try { @@ -873,6 +873,8 @@ private async Task ExecuteSingleRequest(OrganizationRequest req, Operation return true; } } + + return true; } private void ShowProgress(IQueryExecutionOptions options, OperationNames operationNames, EntityMetadata meta) @@ -941,57 +943,47 @@ private async Task ProcessBatch(ExecuteMultipleRequest req, OperationNames throw new FaultException(_fault, new FaultReason(_fault.Message)); } + List retryRequests; + if (ContinueOnError) { + // The server will already have tried to execute every request, so we can just pull the ones + // that have a fault that we know we can retry var retryableErrors = errorResponses.Where(item => IsRetryableFault(item.Fault)).ToList(); - - if (retryableErrors.Count > 0) - { - // Create a new ExecuteMultipleRequest with all the requests that haven't been processed yet - var retryReq = new ExecuteMultipleRequest - { - Requests = new OrganizationRequestCollection(), - Settings = new ExecuteMultipleSettings - { - ContinueOnError = IgnoresSomeErrors, - ReturnResponses = responseHandler != null - } - }; - - foreach (var errorItem in retryableErrors) - retryReq.Requests.Add(req.Requests[errorItem.RequestIndex]); - - // Wait and retry - await Task.Delay(TimeSpan.FromSeconds(2), options.CancellationToken); - req = retryReq; - continue; - } + retryRequests = retryableErrors.Select(item => req.Requests[item.RequestIndex]).ToList(); } else { + // The server will have stopped at the first fault. If that was a retryable fault, add that + // and all the subsequent requests to try again var firstRetryableError = errorResponses.FirstOrDefault(item => IsRetryableFault(item.Fault)); - if (firstRetryableError != null) + if (firstRetryableError == null) + retryRequests = new List(); + else + retryRequests = req.Requests.Skip(firstRetryableError.RequestIndex).ToList(); + } + + if (retryRequests.Count > 0) + { + // Create a new ExecuteMultipleRequest with all the requests that haven't been processed yet + var retryReq = new ExecuteMultipleRequest { - // Create a new ExecuteMultipleRequest with all the requests that haven't been processed yet - var retryReq = new ExecuteMultipleRequest + Requests = new OrganizationRequestCollection(), + Settings = new ExecuteMultipleSettings { - Requests = new OrganizationRequestCollection(), - Settings = new ExecuteMultipleSettings - { - ContinueOnError = IgnoresSomeErrors, - ReturnResponses = responseHandler != null - } - }; + ContinueOnError = IgnoresSomeErrors, + ReturnResponses = responseHandler != null + } + }; - for (var i = firstRetryableError.RequestIndex; i < req.Requests.Count; i++) - retryReq.Requests.Add(req.Requests[i]); + foreach (var retryRequest in retryRequests) + retryReq.Requests.Add(retryRequest); - // Wait and retry - await Task.Delay(TimeSpan.FromSeconds(2), options.CancellationToken); - req = retryReq; - continue; - } + // Wait and retry + await Task.Delay(TimeSpan.FromSeconds(2), options.CancellationToken); + req = retryReq; + continue; } break;