private void ProcessQueuedJob(CustomJob postImage)
        {
            postImage.Require(nameof(postImage));

            var isRetry = Context.PreEntityImages.FirstOrDefault().Value?.ToEntity <CustomJob>().StatusReason
                          == CustomJob.StatusReasonEnum.Retry;

            if (isRetry)
            {
                Log.Log("Retrying ...");
            }

            Log.Log("Setting job to 'running' ...");
            Service.Update(
                new CustomJob
            {
                Id           = postImage.Id,
                StatusReason = CustomJob.StatusReasonEnum.Running
            });
            Log.Log("Set job to 'running'.");

            var run = JobRunFactory.GetJobRun(postImage, isRetry, Service, ServiceFactory, Log);

            run.Process();
        }
示例#2
0
 protected JobRun(CustomJob job, EngineParams engineParams, IOrganizationService service, CrmLog log)
 {
     Job          = job;
     EngineParams = engineParams;
     Service      = service;
     this.log     = log;
 }
        private void ValidateJobParams(CustomJob postImage)
        {
            postImage.Require(nameof(postImage));

            if (postImage.ActionName != null && postImage.Workflow != null && postImage.URL.IsFilled())
            {
                throw new InvalidPluginExecutionException("Either an action or workflow or URL can be specified.");
            }

            if (string.IsNullOrEmpty(postImage.ActionName) && postImage.Workflow == null && postImage.URL.IsEmpty())
            {
                throw new InvalidPluginExecutionException("An action or workflow or URL must be specified.");
            }

            if (postImage.TargetID != null && postImage.TargetXML != null)
            {
                throw new InvalidPluginExecutionException("Either a target ID or XML can be specified.");
            }

            if ((postImage.TargetID != null || postImage.TargetXML != null) &&
                string.IsNullOrEmpty(postImage.TargetLogicalName))
            {
                throw new InvalidPluginExecutionException("Target logical name must be specified.");
            }
        }
        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.");
                }
            }
        }
        public static void UpdateRetryTargetDate(IOrganizationService service, CustomJob job, CrmLog log)
        {
            DateTime?nextRecurrence;

            if (job.RetrySchedule == null)
            {
                log.Log("No retry schedule.");
                nextRecurrence = DateTime.UtcNow.AddMinutes(1);
            }
            else
            {
                log.Log($"Getting next retry occurrence for {job.RetrySchedule}.", LogLevel.Debug);
                var action = new GlobalActions.ldv_CustomJobGetNextRecurrenceDate(
                    new EntityReference(RecurrenceRule.EntityLogicalName, job.RetrySchedule.Value), service);
                nextRecurrence = action.Execute().NextTargetDate;
                log.Log($"Next retry occurrence: '{nextRecurrence}'.");
            }

            var targetDate = nextRecurrence > new DateTime(1900) ? nextRecurrence : null;

            log.Log($"Updating target date to '{targetDate}' UTC ...", LogLevel.Debug);
            service.Update(
                new CustomJob
            {
                Id         = job.Id,
                TargetDate = targetDate
            });
            log.Log($"Updated target date to '{targetDate}' UTC");
        }
        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());
        }
示例#7
0
 protected JobTarget(CustomJob job, IOrganizationService service, IOrganizationServiceFactory serviceFactory,
                     CrmLog log)
 {
     Job            = job;
     Service        = service;
     ServiceFactory = serviceFactory;
     this.log       = log;
 }
示例#8
0
        internal static JobRun GetJobRun(CustomJob job, bool isRetry, IOrganizationService service,
                                         IOrganizationServiceFactory factory, CrmLog log)
        {
            try
            {
                log.LogFunctionStart();

                if (IsRecurrent(job, log))
                {
                    return(new RecurrentRunJob(job, service, log));
                }

                log.Log("Single run job.");

                JobTarget target;

                if (IsSingleOrNoTarget(job, log))
                {
                    target = new SingleTargetJob(job, service, factory, log);
                }
                else if (IsPaging(job, log))
                {
                    if (isRetry)
                    {
                        target = new PagingRetryJob(job, service, factory, log);
                    }
                    else
                    {
                        target = new PagingNormalJob(job, service, factory, log);
                    }
                }
                else
                {
                    if (isRetry)
                    {
                        target = new NoPagingRetryJob(job, service, factory, log);
                    }
                    else
                    {
                        target = new NoPagingNormalJob(job, service, factory, log);
                    }
                }

                return(new SingleRunJob(job, target, service, log));
            }
            catch (Exception ex)
            {
                log.Log(ex);
                throw;
            }
            finally
            {
                log.LogFunctionEnd();
            }
        }
        internal static void SetStatus(IOrganizationService service, CustomJob.StatusReasonEnum status,
                                       Guid jobId, bool isTriggerRecurrence)
        {
            var job =
                new CustomJob
            {
                Id           = jobId,
                StatusReason = status
            };

            if (isTriggerRecurrence)
            {
                job.RecurrenceUpdatedTrigger = new Random().Next(111111, 99999999).ToString();
                job.TargetDate = new DateTime(2100, 1, 1);
            }

            service.Update(job);
        }
示例#10
0
    private bool CreateJob(SPWebApplication site)
    {
        bool jobCreated = false;

        try
        {
            // schedule job for once a day
            CustomJob       job      = new CustomJob(JobName, site);
            SPDailySchedule schedule = new SPDailySchedule();
            schedule.BeginHour = 0;
            schedule.EndHour   = 1;
            job.Schedule       = schedule;
            job.Update();
        }
        catch (Exception)
        {
            return(jobCreated);
        }
        return(jobCreated);
    }
示例#11
0
        private static bool IsRecurrent(CustomJob job, CrmLog log)
        {
            try
            {
                log.LogFunctionStart();

                var isRecurrent = job.RecurrentJob == true;
                log.Log($"{isRecurrent}");
                return(isRecurrent);
            }
            catch (Exception ex)
            {
                log.Log(ex);
                throw;
            }
            finally
            {
                log.LogFunctionEnd();
            }
        }
示例#12
0
        private static bool IsPaging(CustomJob job, CrmLog log)
        {
            try
            {
                log.LogFunctionStart();

                var isPaging = job.RecordsPerPage > 0;
                log.Log($"{isPaging}");
                return(isPaging);
            }
            catch (Exception ex)
            {
                log.Log(ex);
                throw;
            }
            finally
            {
                log.LogFunctionEnd();
            }
        }
示例#13
0
        private static bool IsSingleOrNoTarget(CustomJob job, CrmLog log)
        {
            try
            {
                log.LogFunctionStart();

                var isSingleOrNoTarget = string.IsNullOrWhiteSpace(job.TargetLogicalName) ||
                                         job.TargetID?.Split(',').Length <= 1;
                log.Log($"{isSingleOrNoTarget}");
                return(isSingleOrNoTarget);
            }
            catch (Exception ex)
            {
                log.Log(ex);
                throw;
            }
            finally
            {
                log.LogFunctionEnd();
            }
        }
        internal static CustomJob BuildSubJob(CustomJob parentJob, CustomJob.StatusReasonEnum status, string suffix)
        {
            var fieldExclusions =
                new[]
            {
                CustomJob.Fields.CustomJobId,
                CustomJob.Fields.Name,
                CustomJob.Fields.RecurrentJob,
                CustomJob.Fields.RunTrigger,
                CustomJob.Fields.RecurrenceUpdatedTrigger,
                CustomJob.Fields.ParentJob,
                CustomJob.Fields.DeleteOnSuccess,
                CustomJob.Fields.RetrySchedule,
                CustomJob.Fields.Status,
                CustomJob.Fields.StatusReason,
                CustomJob.Fields.LatestRunMessage,
                CustomJob.Fields.MarkForWaiting,
                CustomJob.Fields.PreviousTargetDate,
                CustomJob.Fields.ParentRecurrent
            };
            var extendingjob = new CustomJob();

            foreach (var key in parentJob.Attributes.Keys.Except(fieldExclusions))
            {
                extendingjob[key] = parentJob[key];
            }

            extendingjob.Name            = $"{parentJob.Name} | {suffix}";
            extendingjob.DeleteOnSuccess = parentJob.DeleteSubJobsOnSuccess;
            extendingjob.StatusReason    = status;
            extendingjob.ParentJob       = parentJob.Id;
            extendingjob.ParentRecurrent = parentJob.RecurrentJob;
            extendingjob.RetrySchedule   = parentJob.SubJobsRetrySchedule;
            extendingjob.MarkForWaiting  = false;

            return(extendingjob);
        }
示例#15
0
        private static bool IsSinglePage(CustomJob job, CrmLog log, IOrganizationService service)
        {
            if (string.IsNullOrWhiteSpace(job.TargetXML) || IsSingleOrNoTarget(job, log))
            {
                return(true);
            }

            log.Log("Converting FetchXML to QueryExpression ...", LogLevel.Debug);
            var query = ((FetchXmlToQueryExpressionResponse)
                         service.Execute(
                             new FetchXmlToQueryExpressionRequest
            {
                FetchXml = job.TargetXML
            })).Query;

            log.Log("Converted.", LogLevel.Debug);

            // we only need to check if there are more pages or not
            query.ColumnSet = new ColumnSet(false);

            query.PageInfo =
                new PagingInfo
            {
                Count        = job.RecordsPerPage ?? 5000,
                PageNumber   = job.PageNumber ?? 1,
                PagingCookie = job.PagingCookie
            };

            log.Log($"Retrieving a max of {query.PageInfo.Count} per page ...", LogLevel.Debug);
            log.Log($"Retrieving page {query.PageInfo.PageNumber} ...", LogLevel.Debug);
            var result = service.RetrieveMultiple(query);

            log.Log($"More records: {result.MoreRecords}.");

            return(result.MoreRecords);
        }
示例#16
0
        public ActionResult ListeOffreJson()
        {
            db.Configuration.ProxyCreationEnabled = false;
            String  libelleSearch = Request["libelleSearch"];
            String  locationSearch = Request["locationSearch"];
            Decimal categoriesSearch = 0, domaine = 0;
            Double  timePost = 0;

            if (!string.IsNullOrEmpty(Request["categoriesSearch"]))
            {
                categoriesSearch = Convert.ToDecimal(Request["categoriesSearch"]);
            }
            if (!string.IsNullOrEmpty(Request["domaine"]))
            {
                domaine = Convert.ToDecimal(Request["domaine"]);
            }

            if (!string.IsNullOrEmpty(Request["timePost"]))
            {
                timePost = Convert.ToDouble(Request["timePost"]);
            }

            String anneeExp        = Request["anneeExp"];
            String type            = Request["type"];
            String datePostedRadio = Request["datePostedRadio"];
            int    page            = Request["page"].AsInt();
            int    limit           = 4;

            Console.WriteLine("libelleSearch=" + libelleSearch + ", locationSearch=" + locationSearch + "+categoriesSearch=" + categoriesSearch);

            var listPostuler = db.Postuler.AsQueryable();

            listPostuler = listPostuler.Where(p => p.Job.archived == 1 && p.Inscrire.type == "client" && p.Job.status == 1 && p.approbation.Equals("1") && DateTime.Compare((DateTime)p.Job.dateFinOffre, DateTime.Now) > 0).OrderByDescending(p => p.Job.created);
            if (!string.IsNullOrEmpty(libelleSearch))
            {
                listPostuler = listPostuler.Where(p => p.Job.titre.Contains(libelleSearch));
            }
            if (!string.IsNullOrEmpty(locationSearch))
            {
                listPostuler = listPostuler.Where(p => p.Job.ville.Contains(locationSearch));
            }
            if (!string.IsNullOrEmpty(anneeExp))
            {
                listPostuler = listPostuler.Where(p => p.Job.margeExperience.Contains(anneeExp));
            }
            if (!string.IsNullOrEmpty(type))
            {
                listPostuler = listPostuler.Where(p => p.Job.heureTravail.Contains(type));
            }
            if (categoriesSearch != 0)
            {
                listPostuler = listPostuler.Where(p => p.Job.Cat_id == categoriesSearch);
            }
            if (domaine != 0)
            {
                listPostuler = listPostuler.Where(p => p.Job.Categorie.Types.id == domaine);
            }
            if (timePost != 0)
            {
                DateTime diff = DateTime.Now.AddDays(-timePost);
                listPostuler = listPostuler.Where(p => p.Job.created <= DateTime.Now && p.Job.created >= diff);
            }
            var count = listPostuler.Count();
            //if (!libelleSearch.Equals(""))  listPostuler = from c in listPostuler where c.Job.titre.Contains(libelleSearch) select c;
            //if (!locationSearch.Equals("")) listPostuler = from c in listPostuler where c.Job.ville.Contains(locationSearch) select c;

            List <CustomJob> listResult = new List <CustomJob>();

            foreach (Postuler item in listPostuler.ToList().ToPagedList(page, limit))
            {
                CustomJob customJob = new CustomJob();
                customJob.id             = item.Job.id;
                customJob.titre          = item.Job.titre;
                customJob.ville          = item.Job.ville;
                customJob.heureTravail   = item.Job.heureTravail;
                customJob.remuneration   = item.Job.remuneration;
                customJob.dateEntre      = item.Job.dateEntre;
                customJob.profil         = item.Inscrire.profil;
                customJob.nom            = item.Inscrire.nom;
                customJob.immediat       = item.Job.immediat;
                customJob.negociable     = "" + item.Job.negociable;
                customJob.salaireAnnuel  = "" + item.Job.salaireAnnuel;
                customJob.remuneration_n = "" + item.Job.remunerationN;
                listResult.Add(customJob);
            }

            return(Json(new { count = count, limit = limit, datas = listResult }, JsonRequestBehavior.AllowGet));
        }
 public SingleTargetJob(CustomJob job, IOrganizationService service, IOrganizationServiceFactory factory,
                        CrmLog log) : base(job, service, factory, log)
 {
 }
示例#18
0
 public ProgramStarter(CustomJob job)
 {
     _job = job;
 }
 public NoPagingRetryJob(CustomJob job, IOrganizationService service, IOrganizationServiceFactory serviceFactory,
                         CrmLog log) : base(job, service, serviceFactory, log)
 {
 }
 public NoPagingRetryJob(CustomJob job, EngineParams engineParams, IOrganizationService service, CrmLog log)
     : base(job, engineParams, service, log)
 {
 }
 public SingleRunJob(CustomJob job, JobTarget target, IOrganizationService service, CrmLog log)
     : base(job, service, log)
 {
     JobTarget = target;
 }
 protected JobRun(CustomJob job, IOrganizationService service, CrmLog log)
 {
     Job      = job;
     Service  = service;
     this.log = log;
 }
 protected MultiTargetJob(CustomJob job, EngineParams engineParams, IOrganizationService service, CrmLog log)
     : base(job, engineParams, service, log)
 {
 }
示例#24
0
 protected NoPagingJob(CustomJob job, EngineParams engineParams, IOrganizationService service, CrmLog log)
     : base(job, engineParams, service, log)
 {
 }
        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.");
            }
        }
示例#26
0
 public PagingNormalJob(CustomJob job, IOrganizationService service, IOrganizationServiceFactory serviceFactory,
                        CrmLog log) : base(job, service, serviceFactory, log)
 {
 }
示例#27
0
 public RecurrentRunJob(CustomJob job, IOrganizationService service, CrmLog log) : base(job, service, log)
 {
 }
示例#28
0
 public RecurrentRunJob(CustomJob job, EngineParams engineParams, IOrganizationService service, CrmLog log)
     : base(job, engineParams, service, log)
 {
 }
        private string BuildJobName(CustomJob customJob)
        {
            customJob.Require(nameof(customJob));

            CustomJob preImage = null;

            if (Context.MessageName == "Update")
            {
                preImage = Context.PreEntityImages?.FirstOrDefault().Value?.ToEntity <CustomJob>();

                if (preImage == null)
                {
                    throw new InvalidPluginExecutionException("A full pre image must be registered on this plugin step.");
                }
            }

            if (Context.MessageName == "Create" && !string.IsNullOrEmpty(customJob.Name))
            {
                Log.Log("'Create' message and name is filled; using the custom name.");
                return(customJob.Name);
            }

            var customJobTemp =
                new CustomJob
            {
                Id         = customJob.Id,
                ActionName = customJob.ActionName,
                Workflow   = customJob.Workflow
            };

            Log.Log("Loading lookup labels ...");
            customJobTemp.LoadLookupLabels(Service);
            Log.Log("Loaded lookup labels.");

            var label   = customJobTemp.WorkflowLabels?.FirstOrDefault(p => p.Key == 1033).Value;
            var newName = $"{customJob.TargetLogicalName}" +
                          " (" + (string.IsNullOrEmpty(customJob.TargetID)
                                        ? (string.IsNullOrEmpty(customJob.TargetXML) ? "no target" : "multi-target")
                                        : customJob.TargetID) + ")" +
                          $"{(string.IsNullOrEmpty(customJobTemp.ActionName) ? "" : " : " + customJobTemp.ActionName)}" +
                          $"{(string.IsNullOrEmpty(label) ? "" : " : " + label)}";

            Log.Log($"Assumed new name: {newName}.");

            if (Context.MessageName == "Update" && preImage != null)
            {
                Log.Log($"Updating message; comparing updated name.");
                customJobTemp =
                    new CustomJob
                {
                    Id         = customJob.Id,
                    ActionName = preImage.ActionName,
                    Workflow   = preImage.Workflow
                };

                Log.Log("Loading lookup labels of pre-image ...");
                customJobTemp.LoadLookupLabels(Service);
                Log.Log("Loaded lookup labels of pre-image.");

                var preLabel = customJobTemp.WorkflowLabels?.FirstOrDefault(p => p.Key == 1033).Value;
                var preName  = $"{preImage.TargetLogicalName}" +
                               " (" + (string.IsNullOrEmpty(preImage.TargetID)
                                                ? (string.IsNullOrEmpty(preImage.TargetXML) ? "no target" : "multi-target")
                                                : preImage.TargetID) + ")" +
                               $"{(string.IsNullOrEmpty(customJobTemp.ActionName) ? "" : " : " + customJobTemp.ActionName)}" +
                               $"{(string.IsNullOrEmpty(preLabel) ? "" : " : " + preLabel)}";
                Log.Log($"Pre-image name: {preName}.");

                var existingName = customJob.Name;
                newName = (string.IsNullOrEmpty(existingName) || preName == existingName) ? newName : existingName;
                Log.Log($"Final new name: {newName}.");
            }

            return(newName.Trim(' ').Trim(':').Trim(' '));
        }
        protected override void ExecuteLogic()
        {
            orgId  = Context.OrganizationId.ToString();
            config = GetGenericConfig(Service, orgId).ToEntity <CommonConfiguration>();

            CustomJob target = null;
            CustomJob image  = null;

            try
            {
                // get the triggering record
                var targetGeneric = (Entity)Context.InputParameters["Target"];
                target = targetGeneric.ToEntity <CustomJob>();
                image  = Context.PostEntityImages.FirstOrDefault().Value?.ToEntity <CustomJob>();

                // sync
                if (Context.Mode == 0)
                {
                    PerformSyncActions(targetGeneric);
                    return;
                }

                PerformAsyncActions(targetGeneric);
            }
            catch (Exception ex)
            {
                try
                {
                    if (target?.Id != null)
                    {
                        try
                        {
                            Log.Log("Logging failure ...");
                            Service.Update(
                                new CustomJob
                            {
                                Id = target.Id,
                                LatestRunMessage   = "Job handler failed to execute.\r\n" + BuildExceptionMessage(ex),
                                PreviousTargetDate = DateTime.UtcNow,
                                TargetDate         = null
                            });
                            Log.Log("Logged.");

                            // if a recurrent job throws an exception (parent), then check for retry
                            // normally those jobs create sub-jobs that handle their own retry, but this is in case
                            // the main job itself fails, which should be extremely rare
                            if (image?.RecurrentJob == true && image.RetrySchedule != null)
                            {
                                UpdateRetryTargetDate(Service, target, Log);

                                Log.Log($"Updating status of job to 'Waiting' ...");
                                SetStatus(Service, CustomJob.StatusReasonEnum.Waiting, target.Id, false);
                                Log.Log($"Updated status of job 'Waiting'.");
                            }
                        }
                        catch
                        {
                            // ignored
                        }

                        if (image?.RetrySchedule == null)
                        {
                            Log.Log($"Setting job to 'Failure' ...");
                            Service.Update(
                                new CustomJob
                            {
                                Id           = target.Id,
                                Status       = CustomJob.StatusEnum.Inactive,
                                StatusReason = CustomJob.StatusReasonEnum.Failure
                            });
                            Log.Log($"Set job to 'Failure'.");
                        }
                    }
                }
                catch
                {
                    Log.Log("Failed to set job 'failed' status.");
                }

                throw;
            }
        }