/// <summary> /// Disallows the specified today. /// </summary> /// <param name="today">The today.</param> /// <param name="startTime">The start time.</param> /// <param name="endTime">The end time.</param> /// <param name="weekdays">The weekdays.</param> /// <returns>Returns true if execution should be allowed else false</returns> internal static bool Disallow(DateTime today, TimeSpan startTime, TimeSpan endTime, Weekdays weekdays) { TimeSpan now = today.TimeOfDay; ///Out of the time range with start and time on the same day return(((now < startTime || endTime < now) && startTime < endTime) ///Out of time range and job time spanning across the days || ((endTime < now && now < startTime) && endTime < startTime) ///Not a valid weekday || !Util.HasWeekday(weekdays, Util.GetWeekday(today.DayOfWeek))); }
/// <summary> /// Returns the nexts scedule from the specified date time /// </summary> /// <param name="from">From date time</param> /// <returns></returns> DateTime IRecur.Next(DateTime from) { DateTime original = from; while (true) { Weekdays thisDay = Utils.GetWeekday(from.DayOfWeek); ///If its all weekdays, just add the next day if (_weekdays == Weekdays.All) { if (thisDay == Weekdays.Saturday) { from = from.AddDays((_repeat * 7) + 1); } else { from = from.AddDays(1); } } else { int d, i = (int)from.DayOfWeek; ///Find number of days for the next valid weekday for (d = 0; !Utils.HasWeekday(_weekdays, Utils.GetWeekday(i)); i++) { d++; } ///calculate next valid weekday to run the job i = (d + (int)from.DayOfWeek) % 7; ///if the next valid day is >= the from weekday simple add the day else going back to next week if (i >= (int)from.DayOfWeek) { from = from.AddDays(d); } else { from = from.AddDays(d + (_repeat * 7)); } } ///If the date is same the one passed in the add a day if (original == from) { from = from.AddDays(1); continue; } return(from); } }
/// <summary> /// Runs the task. /// </summary> /// <param name="state">The state.</param> private void RunTask(object state) { if (!_isStarted) { return; } TaskWrapper taskWrapper = null; lock (_sync) { // if this is coming as part of the timer trigger close down the timer if (_timer != null) { TraceInformation("Disabling the timer"); _timer.Change(Timeout.Infinite, Timeout.Infinite); } _jobsInQueue--; DateTime today = Now; TimeSpan now = today.TimeOfDay; ///Check whether it is within the allowed time if (Time.Disallow(today, _dayStartTime, _dayEndTime, _weekdays)) { TraceInformation("Not allowed to run at this time"); ///If there are more queued items, release this thread task if (_jobsInQueue > 0) { TraceInformation("Have more items in queue"); return; } ///If the number of thread running is more that minimum thread, remove 1 and return; if (_freeTaskPool.Count > 0 && _allTasks.Count > MinInstances) { TraceInformation("Releasing a task"); taskWrapper = _freeTaskPool[0]; taskWrapper.Release(); _freeTaskPool.Remove(taskWrapper); _allTasks.Remove(taskWrapper); } if (_timer == null) { TraceInformation("Timer created"); _timer = new Timer(new TimerCallback(RunTask), null, Timeout.Infinite, Timeout.Infinite); } ///Do it only for the last thread. if (_parallelInstances == 0 && _allTasks.Count == MinInstances) { DateTime st = new DateTime(today.Year, today.Month, today.Day, _dayStartTime.Hours, _dayStartTime.Minutes, _dayStartTime.Seconds, DateTimeKind.Unspecified); ///if today is not allowed weekday, move it to next start of the day if (!Utils.HasWeekday(_weekdays, Utils.GetWeekday(today.DayOfWeek)) || today > st) { st = st.AddDays(1).Date; //Setting it to next day 12:00 AM } ///Find the differene by converting to UTC time to make sure daylight cutover are accounted TimeSpan wait = TimeZoneInfo.ConvertTimeToUtc(st, _timeZoneInfo) - TimeZoneInfo.ConvertTimeToUtc(today, _timeZoneInfo); ///This is for the timer job _jobsInQueue++; _timer.Change((long)wait.TotalMilliseconds, Timeout.Infinite); //_timer.Change(_idlePollingPeriod, Timeout.Infinite); TraceInformation("wait for {0} before it starts", wait); } return; } if (_freeTaskPool.Count == 0) { AddTask(1); } if (_freeTaskPool.Count > 0) { taskWrapper = _freeTaskPool[0]; _freeTaskPool.RemoveAt(0); } else { ///There are no parallel capacity so exit TraceInformation("There is no more thread capacity for this task runner"); return; } _parallelInstances++; } TraceInformation("Free Task {0}, All Task {1}, Parallel Instanse {2}, Queue {3}", _freeTaskPool.Count, _allTasks.Count, _parallelInstances, _jobsInQueue); ExecutionState executionState = taskWrapper.RunTask(); switch (executionState) { case ExecutionState.Executed: //Since there is work it should also create one more instance for parallel tasking lock (_sync) { ///Reduce the number of instances _parallelInstances--; ///Put back the task into the free pool _freeTaskPool.Add(taskWrapper); //Since executed successfully it should go back for execution QueueTask(); //there is more capacity possible, put one more to work if (_jobsInQueue + _parallelInstances < this.MaxInstances) { QueueTask(); } } RaiseComplete(taskWrapper.Context); break; case ExecutionState.Stop: //Since the task has indicated to stop, release it lock (_sync) { ///Reduce the number of instances _parallelInstances--; _allTasks.Remove(taskWrapper); _freeTaskPool.Remove(taskWrapper); ///If that the last instance then stop the task if (_jobsInQueue == 0 && _parallelInstances == 1) { Stop(); } } break; case ExecutionState.Recycle: //Since the task has indicated to recycle it, release it and add new. lock (_sync) { ///Reduce the number of instances _parallelInstances--; _allTasks.Remove(taskWrapper); _freeTaskPool.Remove(taskWrapper); AddTask(1); QueueTask(); } break; case ExecutionState.Idle: case ExecutionState.Exception: //If there is an unhandled exception we should treat it as idle else it will lead to CPU racing //This is tough task :-), not enough work to do, start firing ;-) lock (_sync) { ///Reduce the number of instances _parallelInstances--; ///Put back the task into the free pool _freeTaskPool.Add(taskWrapper); //There are other items in the queue do nothing come out. if (_jobsInQueue > 0) { break; } ///Fire 1 task, save resources ONLY if task return Idle if (_allTasks.Count > MinInstances) { taskWrapper = _freeTaskPool[0]; taskWrapper.Release(); _freeTaskPool.Remove(taskWrapper); _allTasks.Remove(taskWrapper); } ///This is the last thread, put a timer since there is no work, lets wait for 5 seconds. ///This can be further imporved by having increasing delay i.e. wait for 5, 10, 15 when we ///get work reset it to 5 secs if (_timer == null) { _timer = new Timer(new TimerCallback(RunTask), null, Timeout.Infinite, Timeout.Infinite); } ///Wait for idle period to see whether there is something to do ///Do it only for the last thread and there is no job in the queue if (_parallelInstances == 0 && _jobsInQueue == 0) { ///This is for the timer job _jobsInQueue++; _timer.Change((long)_idlePollingPeriod, Timeout.Infinite); TraceInformation("Is in timer mode"); } } break; default: ///This could be for any new state lock (_sync) { ///Reduce the number of instances _parallelInstances--; ///Put back the task into the free pool _freeTaskPool.Add(taskWrapper); QueueTask(); } break; } }
/// <summary> /// Runs the task. /// </summary> /// <param name="state">The state.</param> private void RunTask(object state) { ///Task not started, call should never come here if (_timer == null) { return; } DateTime today = Now; ///Not in the limit of the date time range if (today > _endDateTime) { Stop(); return; } ///Sleep until the interval duration before start time if (today < _startDateTime) { TimeSpan wait = TimeZoneInfo.ConvertTimeToUtc(_startDateTime, _timeZoneInfo).Subtract(TimeZoneInfo.ConvertTimeToUtc(today, _timeZoneInfo)); TraceInformation("will wait for {0} before it starts", wait); _timer.Change((long)wait.TotalMilliseconds, _interval); return; } ///Not in the range of time of the day or avalid weekday if (Time.Disallow(today, _dayStartTime, _dayEndTime, _weekdays)) { DateTime st = new DateTime(today.Year, today.Month, today.Day, _dayStartTime.Hours, _dayStartTime.Minutes, _dayStartTime.Seconds, DateTimeKind.Unspecified); ///If its not an allowed weekday, wait until next start of day if (!Utils.HasWeekday(_weekdays, Utils.GetWeekday(today.DayOfWeek)) || today > st) { st = st.AddDays(1).Date; } ///Find the differene by converting to UTC time to make sure daylight cutover are accounted TimeSpan wait = TimeZoneInfo.ConvertTimeToUtc(st, _timeZoneInfo) - TimeZoneInfo.ConvertTimeToUtc(today, _timeZoneInfo); //TimeSpan wait = st.Subtract(now); TraceInformation("will wait for {0} before it starts", wait); _timer.Change((long)wait.TotalMilliseconds, _interval); return; } if (_recurrence > 0 || _recurrence == -1) { ///Stop the timer _timer.Change(Timeout.Infinite, _interval); ExecutionState executionState = _task.RunTask(); switch (executionState) { case ExecutionState.Executed: RaiseComplete(_task.Context); break; case ExecutionState.Stop: _task.Release(); Stop(); return; case ExecutionState.Recycle: _task.Release(); _task = new TaskWrapper(this.TaskType, new ExecutionContext(Parameters, this)); break; } if (_recurrence != -1) { _recurrence--; } ///Resume the timer _timer.Change(Interval, _interval); } else { Stop(); TraceInformation("stopped because the reccurence is 0 "); } }
DateTime IRecur.Next(DateTime from) { DateTime original = from; while (true) { ///Set the valid month from = Utils.GetValidMonth(_months, from); //First week if ((_weeks & Weeks.First) == Weeks.First) { while (from.Day < 8) { if (Utils.HasWeekday(_weekdays, Utils.GetWeekday(from.DayOfWeek)) && from != original) { return(from); } from = from.AddDays(1); } } //Second week if ((_weeks & Weeks.Second) == Weeks.Second) { while (from.Day < 15 && from.Day > 7) { if (Utils.HasWeekday(_weekdays, Utils.GetWeekday(from.DayOfWeek)) && from != original) { return(from); } from = from.AddDays(1); } } //Third week if ((_weeks & Weeks.Third) == Weeks.Third) { while (from.Day < 22 && from.Day > 14) { if (Utils.HasWeekday(_weekdays, Utils.GetWeekday(from.DayOfWeek)) && from != original) { return(from); } from = from.AddDays(1); } } //Both Fourth & Last week if ((_weeks & (Weeks.Fourth | Weeks.Last)) == (Weeks.Fourth | Weeks.Last)) { while (from.Day > 21) { if (Utils.HasWeekday(_weekdays, Utils.GetWeekday(from.DayOfWeek)) && from != original) { return(from); } from = from.AddDays(1); } } else { //Fourth week if ((_weeks & Weeks.Fourth) == Weeks.Fourth) { while (from.Day < 29 && from.Day > 21) { if (Utils.HasWeekday(_weekdays, Utils.GetWeekday(from.DayOfWeek)) && from != original) { return(from); } from = from.AddDays(1); } } //Last if ((_weeks & Weeks.Last) == Weeks.Last) { int lastWeekDay = GetLastWeekStartDay(from); while (from.Day >= lastWeekDay) { if (Utils.HasWeekday(_weekdays, Utils.GetWeekday(from.DayOfWeek)) && from != original) { return(from); } from = from.AddDays(1); } } } from = from.AddDays(1); } }