public void ScheduledJobShouldExecute() { JobScheduleElement element = new JobScheduleElement() { Name = "Test", RepeatHours = 24, StartOn = DateTime.Now.AddMilliseconds(-500) }; Assert.IsTrue(ScheduledJob.ShouldExecute(element, 1000, DateTime.UtcNow)); element.StartOn = DateTime.Now.AddMilliseconds(-1001); Assert.IsFalse(ScheduledJob.ShouldExecute(element, 1000, DateTime.UtcNow)); element.StartOn = DateTime.Now.AddHours(1); Assert.IsFalse(ScheduledJob.ShouldExecute(element, 1000, DateTime.UtcNow)); element.StartOn = DateTime.Now; Assert.IsTrue(ScheduledJob.ShouldExecute(element, 1000, DateTime.UtcNow)); }
/// <summary> /// Gets a value indicating whether the schedule identified by the given element is ready for execution /// given the provided heartbeat window and current date. /// </summary> /// <param name="element">The element to check.</param> /// <param name="heartbeat">The heartbeat window, in milliseconds.</param> /// <param name="now">The current date, in UTC.</param> /// <param name="executeOn">The concrete execution date, if the job should be executed.</param> /// <returns>True if the schedule should be executed now, false otherwise.</returns> public static bool ShouldExecute(JobScheduleElement element, long heartbeat, DateTime now, out DateTime? executeOn) { if (element == null) { throw new ArgumentNullException("element", "element cannot be null"); } if (element.RepeatHours <= 0) { throw new ConfigurationErrorsException("A job schedule's repeatHours must be greater than 0.", element.ElementInformation.Source, element.ElementInformation.LineNumber); } if (now.Kind != DateTimeKind.Utc) { throw new ArgumentException("now must be in UTC.", "now"); } executeOn = null; bool shouldExecute = false; DateTime startOn = element.StartOn.ToUniversalTime(); if (now >= startOn) { double milliseconds = now.Subtract(startOn).TotalMilliseconds; double repeatMilliseconds = element.RepeatHours * 3600000; if (repeatMilliseconds <= heartbeat) { throw new ConfigurationErrorsException(String.Format(CultureInfo.InvariantCulture, "A job schedule's repeatHours must be greater than the job runner's heartbeat ({0} milliseconds).", heartbeat), element.ElementInformation.Source, element.ElementInformation.LineNumber); } int repeats = (int)Math.Floor(milliseconds / repeatMilliseconds); executeOn = startOn.AddMilliseconds(((repeats + 1) * repeatMilliseconds) - repeatMilliseconds); DateTime nextHeartbeat = now.AddMilliseconds(heartbeat); DateTime prevHeartbeat = now.AddMilliseconds(-1 * heartbeat); shouldExecute = executeOn >= prevHeartbeat && executeOn < nextHeartbeat; } return shouldExecute; }
/// <summary> /// Creates a new scheduled job record for storing in the <see cref="IJobStore"/>. /// </summary> /// <param name="scheduleElement">The configured schedule element to create the record for.</param> /// <param name="jobElement">The configured job element to create the record for.</param> /// <param name="now">The queue and start date to create the record for.</param> /// <returns>A new scheduled job record.</returns> public static JobRecord CreateRecord(JobScheduleElement scheduleElement, JobScheduledJobElement jobElement, DateTime now) { if (scheduleElement == null) { throw new ArgumentNullException("scheduleElement", "scheduleElement cannot be null."); } if (String.IsNullOrEmpty(scheduleElement.Name)) { throw new ArgumentException("scheduleElement cannot have an empty Name.", "scheduleElement"); } if (jobElement == null) { throw new ArgumentNullException("jobElement", "jobElement cannot be null."); } if (String.IsNullOrEmpty(jobElement.JobType)) { throw new ArgumentException("jobElement cannot have an empty JobType.", "jobElement"); } if (now.Kind != DateTimeKind.Utc) { throw new ArgumentException("now must be in UTC.", "now"); } return new JobRecord() { Name = scheduleElement.Name, JobType = jobElement.JobType, QueueDate = now, ScheduleName = scheduleElement.Name, StartDate = now, Status = JobStatus.Started }; }
/// <summary> /// Gets a value indicating whether the schedule identified by the given element is ready for execution /// given the provided heartbeat window and current date. /// </summary> /// <param name="element">The element to check.</param> /// <param name="heartbeat">The heartbeat window, in milliseconds.</param> /// <param name="now">The current date, in UTC.</param> /// <returns>True if the schedule should be executed now, false otherwise.</returns> public static bool ShouldExecute(JobScheduleElement element, long heartbeat, DateTime now) { DateTime? executeOn; return ShouldExecute(element, heartbeat, now, out executeOn); }
public void JobRunnerExecuteScheduledJobs() { JobScheduleElement sched1 = new JobScheduleElement() { Name = "___TEST_SCHED_1___" + Guid.NewGuid().ToString(), RepeatHours = 24, StartOn = DateTime.UtcNow.AddYears(-1).AddMilliseconds(Heartbeat) }; JobScheduleElement sched2 = new JobScheduleElement() { Name = "___TEST_SCHED_2___" + Guid.NewGuid().ToString(), RepeatHours = .5, StartOn = DateTime.UtcNow.AddDays(-1).AddMilliseconds(Heartbeat) }; JobScheduleElement sched3 = new JobScheduleElement() { Name = "___TEST_SCHED_3___" + Guid.NewGuid().ToString(), RepeatHours = .5, StartOn = DateTime.UtcNow.AddDays(1).AddMilliseconds(Heartbeat) }; JobScheduledJobElement job1 = new JobScheduledJobElement() { JobType = JobRecord.JobTypeString(typeof(TestIdJob)) }; JobScheduledJobElement job2 = new JobScheduledJobElement() { JobType = JobRecord.JobTypeString(typeof(TestScheduledJob)) }; sched1.ScheduledJobs.Add(job1); sched1.ScheduledJobs.Add(job2); sched2.ScheduledJobs.Add(job2); sched3.ScheduledJobs.Add(job1); jobRunner.SetSchedules(new JobScheduleElement[] { sched1, sched2, sched3 }); Thread.Sleep(Heartbeat * 2); Assert.AreEqual(2, jobStore.GetJobCount(null, null, sched1.Name)); Assert.AreEqual(1, jobStore.GetJobCount(null, null, sched2.Name)); Assert.AreEqual(0, jobStore.GetJobCount(null, null, sched3.Name)); }