/// <summary> /// Updates the current trigger timer using the specified trigger. /// </summary> /// <param name="trigger">The trigger information.</param> private void OnUpdateTimer(CrawlerTrigger trigger) { // Synchronize access. lock (this.sync) { // Get the current time; DateTime now = DateTime.Now; // Set the current trigger. this.timerTrigger = trigger; // If the trigger timestamp does not meet the minimum trigger delay. if (now + this.minimumTriggerDelay > trigger.Timestamp) { // Disable the timer. this.timer.Change(Timeout.Infinite, Timeout.Infinite); // Execute the trigger now on the thread pool. ThreadPool.QueueUserWorkItem(this.OnTrigger); } else { // Update the timer. this.timer.Change((long)trigger.Timestamp.Subtract(now).TotalMilliseconds, Timeout.Infinite); } } }
/// <summary> /// An event handler called when the trigger timer expires. /// </summary> /// <param name="state">The state.</param> private void OnTrigger(object state) { // The current trigger. KeyValuePair<DateTime, CrawlerTrigger> first; // Synchronize access. lock (this.sync) { // If the trigger list is empty, do nothing. if (this.timeline.Count == 0) return; // Get the first trigger. first = this.timeline.First(); // Check the timer has been triggered for the current timer trigger. Otherwise, return. if (!object.ReferenceEquals(this.timerTrigger, first.Value)) return; // Remove the first trigger from the list. if (!this.timeline.Remove(first.Key)) throw new InvalidOperationException("Internal task scheduler exception: cannot remove an existing trigger."); // Set the current timer trigger to null. this.timerTrigger = null; // If the trigger list is not empty. if (this.timeline.Count > 0) { // Get the next trigger. KeyValuePair<DateTime, CrawlerTrigger> next = this.timeline.First(); // Update the timer. this.OnUpdateTimer(next.Value); } } // Execute the current trigger. first.Value.Execute(); }
/// <summary> /// Removes a trigger from the tasks timeline. /// </summary> /// <param name="trigger">The trigger.</param> public void RemoveTrigger(CrawlerTrigger trigger) { // Synchronize access. lock (this.sync) { // Check the trigger list is not empty. if (this.timeline.Count == 0) throw new InvalidOperationException("Internal task scheduler exception: cannot remove a trigger because the trigger list is empty."); // Get the first trigger. KeyValuePair<DateTime, CrawlerTrigger> first = this.timeline.First(); // Remove the trigger. if (!this.timeline.Remove(trigger.Timestamp)) throw new InvalidOperationException("Internal task schedule exception: cannot remove a trigger because it could not be found."); // If the trigger is the first trigger. if (object.ReferenceEquals(first.Value, trigger)) { // If the trigger list is empty. if (this.timeline.Count == 0) { // Disable the timer. this.timer.Change(Timeout.Infinite, Timeout.Infinite); } else { // Get the next trigger. KeyValuePair<DateTime, CrawlerTrigger> next = this.timeline.First(); // Update the timer. this.OnUpdateTimer(next.Value); } } } }
/// <summary> /// Adds the specified trigger to the timeline. /// </summary> /// <param name="trigger">The trigger.</param> /// <param name="timestamp">The timeline timestamp.</param> private void OnAddTriggerSafe(CrawlerTrigger trigger, out DateTime timestamp) { // Synchronize access. lock (this.sync) { // Get the trigger timestamp. timestamp = trigger.Timestamp; // If the timestamp exists. while (this.timeline.ContainsKey(timestamp)) { // Increment the timestamp. timestamp.AddTicks(1); } // Add the trigger. this.timeline.Add(timestamp, trigger); } }
/// <summary> /// Adds a new trigger to the tasks timeline. /// </summary> /// <param name="trigger">The trigger.</param> /// <param name="timestamp">The timeline timestamp.</param> public void AddTrigger(CrawlerTrigger trigger, out DateTime timestamp) { // Synchronize access. lock (this.sync) { // If the timeline is empty. if (this.timeline.Count == 0) { // Add the trigger to the timeline. this.OnAddTriggerSafe(trigger, out timestamp); // Update the timer. this.OnUpdateTimer(trigger); } else { // The first trigger. KeyValuePair<DateTime, CrawlerTrigger> first = this.timeline.First(); // Add the trigger to the triggers list. this.OnAddTriggerSafe(trigger, out timestamp); // If the timestamp of the current schedule is smaller than the timestamp of the first schedule. if (trigger.Timestamp < first.Key) { // Update the timer. this.OnUpdateTimer(trigger); } } } }