protected List <CustomJobFailedTarget> GetRetryTargets(int?page = null, int?count = null) { var job = new CustomJob { Id = Job.Id }; if (page != null && count != null) { Log.Log($"Loading retry targets with page {page.Value} and count {count.Value} ..."); job.LoadRelation(CustomJob.RelationNames.CustomJobFailedTargetsOfCustomJob, Service, false, count.Value, page.Value, CustomJobFailedTarget.Fields.ID); Log.Log($"Loaded retry targets with page {page.Value} and count {count.Value}."); } else { Log.Log($"Loading retry targets ..."); job.LoadRelation(CustomJob.RelationNames.CustomJobFailedTargetsOfCustomJob, Service, CustomJobFailedTarget.Fields.ID); Log.Log($"Loaded retry targets."); } var targets = job.CustomJobFailedTargetsOfCustomJob ?? new CustomJobFailedTarget[0]; Log.Log($"Retry targets count: {targets.Length}."); return(targets.ToList()); }
private void PostRunActions(JobRunStatus runStatus) { if (runStatus.IsClose) { var finalStatus = runStatus.IsSuccess ? CustomJob.StatusReasonEnum.Success : CustomJob.StatusReasonEnum.Failure; Close(Service, finalStatus, Job.Id); } if (Job.DeleteOnSuccess == true && runStatus.IsSuccess && runStatus.IsClose && runStatus.RunTargetFailures?.Any() != true) { log.Log("Checking target failures ..."); var job = new CustomJob { Id = Job.Id }; job.LoadRelation(CustomJob.RelationNames.CustomJobFailedTargetsOfCustomJob, Service, false, 1); var isFailedExist = job.CustomJobFailedTargetsOfCustomJob?.Any() == true; log.Log($"Failed exist: {isFailedExist}."); if (!isFailedExist) { log.Log("Deleting job ...", LogLevel.Debug); Service.Delete(CustomJob.EntityLogicalName, Job.Id); log.Log("Deleted job."); } } }
private void PerformSyncActions(Entity targetGeneric) { targetGeneric.Require(nameof(targetGeneric)); var customJob = new CustomJob(); // post if ((Context as IPluginExecutionContext)?.Stage == 40) { Log.Log("Processing post-operation actions ..."); var postImage = Context.PostEntityImages.FirstOrDefault().Value?.ToEntity <CustomJob>(); if (postImage == null && Context.MessageName == "Update") { throw new InvalidPluginExecutionException("A full post image must be registered on this plugin step."); } postImage = postImage ?? targetGeneric.ToEntity <CustomJob>(); foreach (var attribute in postImage.Attributes) { customJob[attribute.Key] = attribute.Value; } ValidateJobParams(customJob); if (string.IsNullOrEmpty(customJob.Name)) { Log.Log("Name is empty, updating ..."); Service.Update( new CustomJob { Id = customJob.Id, Name = BuildJobName(customJob) }); Log.Log("Name was empty, updated."); } return; } if (Context.MessageName == "Update") { Log.Log("Update message, fetching target job from CRM ..."); customJob = Service.Retrieve(targetGeneric.LogicalName, targetGeneric.Id, new ColumnSet(true)) .ToEntity <CustomJob>(); Log.Log("Fetched target job from CRM."); } foreach (var attribute in targetGeneric.Attributes) { customJob[attribute.Key] = attribute.Value; } // fill page if empty if (customJob.RecordsPerPage != null && customJob.PageNumber == null) { Log.Log("Records per page set, but not the page number; setting to '1'."); targetGeneric[CustomJob.Fields.PageNumber] = 1; } // clear failed targets as we are starting over and reset retry runs if (customJob.StatusReason == CustomJob.StatusReasonEnum.Draft) { Log.Log("Draft status."); Log.Log("Clearing retry run, page number, cookie, and last message."); targetGeneric[CustomJob.Fields.CurrentRetryRun] = null; targetGeneric[CustomJob.Fields.PageNumber] = null; targetGeneric[CustomJob.Fields.PagingCookie] = null; targetGeneric[CustomJob.Fields.LatestRunMessage] = null; Log.Log("Loading failed targets for this job ..."); var tempJob = new CustomJob { Id = customJob.Id }; tempJob.LoadRelation(CustomJob.RelationNames.CustomJobFailedTargetsOfCustomJob, Service); Log.Log("Loaded failed targets for this job."); if (tempJob.CustomJobFailedTargetsOfCustomJob != null) { Log.Log($"Failed targets: {tempJob.CustomJobFailedTargetsOfCustomJob.Length}."); var failures = tempJob.CustomJobFailedTargetsOfCustomJob; var request = new ExecuteMultipleRequest { Requests = new OrganizationRequestCollection(), Settings = new ExecuteMultipleSettings { ContinueOnError = true, ReturnResponses = false } }; Log.Log($"Deleting failed targets ..."); for (var i = 0; i < Math.Ceiling(failures.Length / 1000d); i++) { request.Requests.Clear(); request.Requests.AddRange(failures.Skip(i * 1000).Take(1000) .Select(failure => new DeleteRequest { Target = new EntityReference(CustomJobFailedTarget.EntityLogicalName, failure.Id) })); Service.Execute(request); } Log.Log($"Deleted failed targets."); } } // cancel active sub-jobs if (customJob.StatusReason == CustomJob.StatusReasonEnum.Draft || customJob.StatusReason == CustomJob.StatusReasonEnum.Cancelled) { Log.Log($"{customJob.StatusReason} status."); var tempJob = new CustomJob { Id = customJob.Id }; Log.Log("Loading active children of this job ..."); var filter = new FilterExpression(); filter.AddCondition(CustomJob.Fields.Status, ConditionOperator.Equal, (int)CustomJob.StatusEnum.Active); tempJob.LoadRelation(CustomJob.RelationNames.CustomJobsOfParentJob, Service, false, filter); Log.Log("Loaded active children of this job."); if (tempJob.CustomJobsOfParentJob != null) { Log.Log($"Active children: {tempJob.CustomJobsOfParentJob.Length}."); foreach (var job in tempJob.CustomJobsOfParentJob) { Log.Log($"Setting sub job '{job.Id}' to cancelled ..."); Service.Update( new CustomJob { Id = job.Id, Status = CustomJob.StatusEnum.Inactive, StatusReason = CustomJob.StatusReasonEnum.Cancelled }); Log.Log($"Set sub job '{job.Id}' to cancelled."); } } } var isNamingFieldsUpdated = targetGeneric.Attributes.Keys .Any(key => new[] { CustomJob.Fields.TargetLogicalName, CustomJob.Fields.ActionName, CustomJob.Fields.Workflow, CustomJob.Fields.TargetID, CustomJob.Fields.TargetXML }.Contains(key)); if (string.IsNullOrEmpty(customJob.Name) || isNamingFieldsUpdated) { targetGeneric[CustomJob.Fields.Name] = BuildJobName(customJob); Log.Log($"Set job name to '{targetGeneric[CustomJob.Fields.Name]}'."); } if (customJob.StatusReason == CustomJob.StatusReasonEnum.Draft && customJob.MarkForWaiting == true && customJob.TargetDate != null && Context.MessageName != "Create") { Log.Log("Setting job to waiting because of flag ..."); targetGeneric[CustomJob.Fields.MarkForWaiting] = false; targetGeneric[CustomJob.Fields.StatusReason] = CustomJob.StatusReasonEnum.Waiting.ToOptionSetValue(); Log.Log("Set job to waiting because of flag."); } }
protected override void ExecuteLogic() { var target = ((Entity)context.InputParameters["Target"]).ToEntity <CustomJob>(); if (target.RecurrenceUpdatedTrigger == null) { log.Log("Recurrence update not triggered. Exiting ..."); return; } var postImage = context.PostEntityImages.FirstOrDefault().Value?.ToEntity <CustomJob>(); if (postImage == null) { throw new InvalidPluginExecutionException("A full post image must be registered on this plugin step."); } var customJob = new CustomJob { Id = target.Id }; log.Log($"Loading related recurrences.", LogLevel.Debug); customJob.LoadRelation(CustomJob.RelationNames.Recurrences, service); if (customJob.Recurrences == null) { if (postImage.RecurrentJob == true) { log.Log("Setting to non-recurrent ...", LogLevel.Debug); service.Update( new CustomJob { Id = customJob.Id, RecurrentJob = false }); log.Log("Set to non-recurrent."); } log.Log($"No recurrences set. Exiting ..."); return; } DateTime?targetDate = null; foreach (var recurrenceRule in customJob.Recurrences) { log.Log($"Getting next recurrence for {recurrenceRule.Id}.", LogLevel.Debug); var action = new GlobalActions.ldv_CustomJobGetNextRecurrenceDate(recurrenceRule.ToEntityReference(), service); var nextRecurrence = action.Execute().NextTargetDate; log.Log($"Next recurrence: '{nextRecurrence}'."); if (nextRecurrence > new DateTime(1900) && (targetDate == null || nextRecurrence < targetDate)) { targetDate = nextRecurrence; } } if (targetDate == null) { log.Log("Updating latest run message and date.", LogLevel.Debug); service.Update( new CustomJob { Id = target.Id, LatestRunMessage = "Recurrence reached its cycle end.", TargetDate = null, PreviousTargetDate = DateTime.UtcNow, Status = CustomJob.StatusEnum.Inactive, StatusReason = CustomJob.StatusReasonEnum.Success }); log.Log("Updated."); return; } log.Log("Updating target date.", LogLevel.Debug); service.Update( new CustomJob { Id = customJob.Id, RecurrentJob = customJob.Recurrences.Any(), TargetDate = targetDate }); }