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(); }
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()); }
protected JobTarget(CustomJob job, IOrganizationService service, IOrganizationServiceFactory serviceFactory, CrmLog log) { Job = job; Service = service; ServiceFactory = serviceFactory; this.log = log; }
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); }
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); }
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(); } }
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(); } }
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); }
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); }
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) { }
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) { }
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."); } }
public PagingNormalJob(CustomJob job, IOrganizationService service, IOrganizationServiceFactory serviceFactory, CrmLog log) : base(job, service, serviceFactory, log) { }
public RecurrentRunJob(CustomJob job, IOrganizationService service, CrmLog log) : base(job, service, log) { }
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; } }