protected List <CustomJobFailedTarget> DeleteSuccessfulFailed(ExecutionFailures failures = null) { var failedTargets = failures?.Exceptions .Select(failure => new CustomJobFailedTarget { ID = failure.Key.ToString() }).ToList(); var retryTargets = GetRetryTargets(); var successfulRetryTargets = failedTargets == null ? retryTargets : retryTargets.Except(failedTargets, new CustomFailedJobComparer()).ToList(); foreach (var successfulTarget in successfulRetryTargets) { log.Log($"Deleting successful target record '{successfulTarget.ID}' ...", LogLevel.Debug); Service.Delete(CustomJobFailedTarget.EntityLogicalName, successfulTarget.Id); log.Log($"Deleted successful target record '{successfulTarget.ID}'."); } var remainingFailures = failedTargets?.Except(successfulRetryTargets).ToList(); if (remainingFailures == null) { return(null); } // set the ID for the remaining failed targets' records // it was built on the fly without retrieve from CRM, so the IDs are empty foreach (var failure in remainingFailures) { var id = retryTargets.FirstOrDefault(retry => retry.ID == failure.ID)?.Id; if (id == null) { continue; } failure.Id = id.Value; } return(remainingFailures); }
protected List <CustomJobFailedTarget> AssociateFailedTargets(ExecutionFailures failures, Guid jobId) { var failedTargets = failures.Exceptions .Select(failure => new CustomJobFailedTarget { ID = jobId == failure.Key ? "No Target" : failure.Key.ToString(), CustomJob = jobId, FailureMessage = BuildNoTraceExceptionMessage(failure.Value), }); var retryTargets = GetRetryTargets(); var newFailedTargets = failedTargets.Except(retryTargets, new CustomFailedJobComparer()).ToList(); foreach (var failedTarget in newFailedTargets) { log.Log($"Creating failed target record for '{failedTarget.ID}' ...", LogLevel.Debug); failedTarget.CustomJob = jobId; Service.Create(failedTarget); log.Log($"Created failed target record for '{failedTarget.ID}'."); } return(newFailedTargets); }
protected ExecutionFailures Execute(JobPagingInfo pagingInfo) { var result = new ExecutionFailures(); var contextService = GetServiceInContext(); var targets = pagingInfo.Targets; Guid workflowId; if (Guid.TryParse(Job.ActionName, out workflowId) || ((workflowId = Job.Workflow.GetValueOrDefault()) != Guid.Empty)) { log.Log($"Running workflow '{workflowId}' ...", LogLevel.Debug); if (targets?.Any() == true) { foreach (var target in targets) { try { log.Log($"Running workflow on '{target}'."); contextService.Execute( new ExecuteWorkflowRequest { EntityId = target, WorkflowId = workflowId }); } catch (Exception ex) { log.Log($"Failed at '{target}':'{ex.Message}'."); result.Exceptions[target] = ex; if (Job.ContinueOnError == false) { break; } } } } else { log.Log("No targets to run workflow on."); } log.Log($"Finished running workflow '{workflowId}'."); } else { var action = new OrganizationRequest(Job.ActionName); if (!string.IsNullOrEmpty(Job.SerialisedInputParams)) { log.Log($"Inputs: '{Job.SerialisedInputParams}'."); action.Parameters.AddRange(GetInputs()); } log.Log($"Executing action '{Job.ActionName}' ...", LogLevel.Debug); if (targets?.Any() == true) { foreach (var target in targets) { try { log.Log($"Executing action on '{target}' ...", LogLevel.Debug); action["Target"] = new EntityReference(Job.TargetLogicalName, target); contextService.Execute(action); } catch (Exception ex) { log.Log($"Failed at '{target}':'{ex.Message}'."); result.Exceptions[target] = ex; if (Job.ContinueOnError == false) { break; } } } } else if (string.IsNullOrEmpty(Job.TargetLogicalName)) { try { log.Log($"Executing global action ...", LogLevel.Debug); contextService.Execute(action); } catch (Exception ex) { log.Log($"Failed: '{ex.Message}'."); result.Exceptions[Job.Id] = ex; } } log.Log($"Executed action '{Job.ActionName}'."); } return(result); }
protected virtual JobRunStatus ProcessFailure(ExecutionFailures executionResult) { var status = new JobRunStatus(); if (IsNoRetry()) { if (IsSubJob()) { var parentId = Job.ParentJob.Value; if (IsWaitingOnSubJobs(Service, parentId)) { if (Job.IgnoreFailure == true) { log.Log($"Setting status of parent '{parentId}' to 'waiting' ...", LogLevel.Debug); SetStatus(Service, CustomJob.StatusReasonEnum.Waiting, parentId, IsParentRecurrentJob()); log.Log($"Set status of parent '{parentId}' to 'waiting'."); } else { log.Log($"Setting status of parent '{parentId}' to 'failed' ...", LogLevel.Debug); Close(Service, CustomJob.StatusReasonEnum.Failure, parentId, true); log.Log($"Set status of parent '{parentId}' to 'failed'."); } } status.ParentId = parentId; } if (Job.FailureAction != null) { log.Log("Running failure action ..."); try { Service.Execute( new ExecuteWorkflowRequest { EntityId = Job.Id, WorkflowId = Job.FailureAction.Value }); } catch (Exception exception) { log.Log(exception); } log.Log("Finished running failure action."); } status.IsClose = true; } else { if (Job.RetrySchedule != null) { UpdateRetryTargetDate(Service, Job, log); } IncrementRetry(Job.CurrentRetryRun ?? 0); log.Log($"Setting status of job to 'retry' ...", LogLevel.Debug); SetStatus(Service, CustomJob.StatusReasonEnum.Retry, Job.Id, false); log.Log($"Set status of job to 'retry'."); } var failures = executionResult.Exceptions .Select(failure => new CustomJobFailedTarget { ID = failure.Key.ToString(), FailureMessage = BuildNoTraceExceptionMessage(failure.Value) }); status.IsSuccess = false; status.RunTargetFailures = failures.ToList(); return(status); }
protected override JobRunStatus ProcessFailure(ExecutionFailures executionResult) { AssociateFailedTargets(executionResult, Job.Id); DeleteSuccessfulFailed(executionResult); return(base.ProcessFailure(executionResult)); }
protected abstract JobRunStatus ProcessFailurePaging(ExecutionFailures failures, JobPagingInfo pagingInfo);