/// <summary> /// Worker method to handle fualt and track if retry is needed /// </summary> /// <param name="state"></param> /// <param name="fault"></param> /// <returns></returns> private CTCRunMultipleResponse RunMultipleRequestsHandleFault(CTCRunMultipleState state, FaultException <OrganizationServiceFault> fault) { if (fault.Detail.ErrorDetails.Contains("MaxBatchSize")) { //return request index to last position state.RequestIndex -= state.BatchSize; var allowedBatchSize = Convert.ToInt32(fault.Detail.ErrorDetails["MaxBatchSize"]); if (state.TransactionMode != CTCBulkTransactionMode.Single) { state.BatchSize = allowedBatchSize; return(RunMultipleRequestsInternal(state)); } } if (fault.Detail.ErrorDetails.Contains("Server Busy")) { //return request index to last position state.RequestIndex -= state.BatchSize; if (state.RetryCount == 0) { state.Results.StoppedEarly = true; return(state.Results); } Thread.Sleep(state.RetryDelaySeconds * 1000); state.RetryDelaySeconds = state.RetryDelaySeconds * 2; state.RetryCount--; return(RunMultipleRequestsInternal(state)); } throw fault; }
/// <summary> /// Helper method called by public method manages faults - will recurse to handle faults /// </summary> /// <param name="state"></param> /// <returns></returns> private CTCRunMultipleResponse RunMultipleRequestsInternal(CTCRunMultipleState state) { try { while (state.RequestIndex < state.Requests.Count) { LogStatusStart(CrmBulkOpStatusType.BatchStart, "RunMultipleRequestsInternal", 0);; Stopwatch sw = new Stopwatch(); sw.Start(); if (state.TransactionMode == CTCBulkTransactionMode.Single) { RunMultipleRequestsInternalBatchTransaction(state); } else { RunMultipleRequestsInternalBatch(state); } sw.Stop(); LogStatusEnd(CrmBulkOpStatusType.BatchEnd, "RunMultipleRequestsInternal", 0, sw.ElapsedMilliseconds); if (state.Results.StoppedEarly) { return(state.Results); } } } catch (FaultException <OrganizationServiceFault> fault) { return(RunMultipleRequestsHandleFault(state, fault)); } state.Results.StoppedEarly = false; return(state.Results); }
private void RunMultipleRequestsExecuteMultiple(CTCRunMultipleState state, CTCRunMultipleTaskState currentTask, ExecuteMultipleRequest req) { try { var response = _Service.Execute(req) as ExecuteMultipleResponse; if (state.TransactionMode == CTCBulkTransactionMode.None) { var requestList = currentTask.Requests.ToArray <OrganizationRequest>(); foreach (var item in response.Responses) { CTCRunMultipleResponseItem resultItem = new CTCRunMultipleResponseItem(); resultItem.Fault = item.Fault; resultItem.Request = requestList[item.RequestIndex]; resultItem.Response = item.Response; currentTask.Responses.Add(resultItem); } } else { var tranResponse = response.Responses.FirstOrDefault().Response as ExecuteTransactionResponse; int requestIndex = 0; foreach (var item in tranResponse.Responses) { var requestList = currentTask.Requests.ToArray <OrganizationRequest>(); CTCRunMultipleResponseItem resultItem = new CTCRunMultipleResponseItem(); resultItem.Request = requestList[requestIndex]; requestIndex++; resultItem.Response = item; currentTask.Responses.Add(resultItem); } } if ((!state.ContinueOnError) && (response.IsFaulted)) { state.Results.StoppedEarly = true; } } catch (FaultException <OrganizationServiceFault> fault) { RunMultipleRequestsHandleFault(state, fault); } }
/// <summary> /// Worker method to run multiple requests used by all helper methods but can be used standalone to invoke any series of CRM Organization Requests /// </summary> /// <param name="requests"></param> /// <param name="batchSize"></param> /// <param name="returnResponses"></param> /// <param name="continueOnError"></param> /// <param name="retryCount"></param> /// <param name="retrySeconds"></param> /// <param name="transactionMode"></param> /// <returns></returns> public CTCRunMultipleResponse RunMultipleRequests(List <OrganizationRequest> requests, int batchSize = 100, bool returnResponses = true, bool continueOnError = true, int retryCount = 3, int retrySeconds = 10, CTCBulkTransactionMode transactionMode = CTCBulkTransactionMode.None) { CTCRunMultipleState state = new CTCRunMultipleState(); state.RequestIndex = 0; state.Results = new CTCRunMultipleResponse(); state.Results.ResultItems = new List <CTCRunMultipleResponseItem>(); state.RetryCount = retryCount; state.RetryDelaySeconds = retrySeconds; state.BatchSize = batchSize; state.ContinueOnError = continueOnError; state.ReturnResponses = true; state.TransactionMode = transactionMode; state.Requests = requests; return(RunMultipleRequestsInternal(state)); }
private void RunMultipleRequestsInternalBatchTransaction(CTCRunMultipleState state) { CTCRunMultipleTaskState taskState = new CTCRunMultipleTaskState(); taskState.Service = _Service; taskState.ReturnResponses = state.ReturnResponses; taskState.ContinueOnError = state.ContinueOnError; taskState.Requests = state.Requests.Skip(state.RequestIndex).Take(state.BatchSize); state.RequestIndex += state.BatchSize; taskState.Responses = new List <CTCRunMultipleResponseItem>(); ExecuteTransactionRequest req = new ExecuteTransactionRequest() { Requests = new OrganizationRequestCollection() }; req.Requests.AddRange(taskState.Requests); try { var response = _Service.Execute(req) as ExecuteTransactionResponse; int reqIndex = 0; foreach (var item in response.Responses) { CTCRunMultipleResponseItem resultItem = new CTCRunMultipleResponseItem(); resultItem.Request = req.Requests[reqIndex]; reqIndex++; resultItem.Response = item; taskState.Responses.Add(resultItem); } } catch (FaultException <OrganizationServiceFault> fault) { RunMultipleRequestsHandleFault(state, fault); } state.Results.ResultItems.AddRange(taskState.Responses); }
/// <summary> /// Worker method to process batch of requests /// </summary> /// <param name="state"></param> private void RunMultipleRequestsInternalBatch(CTCRunMultipleState state) { var taskStateList = new List <CTCRunMultipleTaskState>(); foreach (var service in _Services) { CTCRunMultipleTaskState taskState = new CTCRunMultipleTaskState(); taskState.Service = service; taskState.ReturnResponses = state.ReturnResponses; taskState.ContinueOnError = state.ContinueOnError; taskState.Requests = state.Requests.Skip(state.RequestIndex).Take(state.BatchSize); state.RequestIndex += state.BatchSize; taskState.Responses = new List <CTCRunMultipleResponseItem>(); taskStateList.Add(taskState); } Parallel.ForEach <CTCRunMultipleTaskState>(taskStateList, new ParallelOptions { MaxDegreeOfParallelism = _Services.Count }, currentTask => { if (currentTask.Requests.Count() > 1) { ExecuteMultipleRequest req = new ExecuteMultipleRequest() { Settings = new ExecuteMultipleSettings(), Requests = new OrganizationRequestCollection() }; req.Settings.ContinueOnError = currentTask.ContinueOnError; req.Settings.ReturnResponses = currentTask.ReturnResponses; if (state.TransactionMode == CTCBulkTransactionMode.None) { req.Requests.AddRange(currentTask.Requests); } else { ExecuteTransactionRequest tranRequest = new ExecuteTransactionRequest() { Requests = new OrganizationRequestCollection() }; tranRequest.Requests.AddRange(currentTask.Requests); tranRequest.ReturnResponses = state.ReturnResponses; req.Requests.Add(tranRequest); req.Settings.ReturnResponses = true; } Stopwatch sw = new Stopwatch(); sw.Start(); LogStatusStart(CrmBulkOpStatusType.ThreadStart, "RunMultipleRequestsInternalBatch", currentTask.Requests.Count()); RunMultipleRequestsExecuteMultiple(state, currentTask, req); sw.Stop(); LogStatusEnd(CrmBulkOpStatusType.ThreadEnd, "RunMultipleRequestsInternalBatch", currentTask.Requests.Count(), sw.ElapsedMilliseconds); } else { var request = currentTask.Requests.FirstOrDefault(); if (request != null) { var response = _Service.Execute(request); CTCRunMultipleResponseItem resultItem = new CTCRunMultipleResponseItem(); resultItem.Fault = null; resultItem.Request = request; resultItem.Response = response; currentTask.Responses.Add(resultItem); } } }); foreach (var task in taskStateList) { state.Results.ResultItems.AddRange(task.Responses); } }