ArrayList FindHook (Hook[] hooks, HookType hookType, HookAction action, Type type, string member) { ArrayList foundHooks = new ArrayList (); if (hooks == null) return foundHooks; foreach (Hook hook in hooks) { if (action == HookAction.InsertBefore && (hook.InsertBefore == null || hook.InsertBefore == "")) continue; else if (action == HookAction.InsertAfter && (hook.InsertAfter == null || hook.InsertAfter == "")) continue; else if (action == HookAction.Replace && (hook.Replace == null || hook.Replace == "")) continue; if (hook.HookType != hookType) continue; if (hook.Select != null) { if (hook.Select.TypeName != null && hook.Select.TypeName != "") if (hook.Select.TypeName != type.FullName) continue; if (hook.Select.TypeMember != null && hook.Select.TypeMember != "") if (hook.Select.TypeMember != member) continue; if (hook.Select.TypeAttributes != null && hook.Select.TypeAttributes.Length > 0) { object[] ats = type.GetCustomAttributes (true); bool found = false; foreach (object at in ats) if (Array.IndexOf (hook.Select.TypeAttributes, at.GetType().FullName) != -1) { found = true; break; } if (!found) continue; } } foundHooks.Add (hook); } return foundHooks; }
private void Worker () { DateTime end_time_of_previous_task = DateTime.MinValue; double duration_of_previous_task = 0.0; Hook pre_hook = null; Hook post_hook = null; ArrayList to_be_executed = new ArrayList (); Hashtable max_priority_by_source = new Hashtable (); int executed_task_count = 0; StringBuilder status_builder = new StringBuilder (); while (running) { status_str = "Finding next task to execute"; lock (big_lock) { // If there are no pending tasks, wait // on our lock and then re-start our // while loop if (tasks_by_tag.Count == 0) { if (EmptyQueueEvent != null) EmptyQueueEvent (); status_str = "Waiting on empty queue"; Monitor.Wait (big_lock); executed_task_count = 0; continue; } if (Debug) Log.Debug ("Running Scheduler inner loop. Pending tasks: {0}", tasks_by_tag.Count); // Walk across our list of tasks and find // the next one to execute. DateTime now = DateTime.Now; DateTime next_trigger_time = DateTime.MaxValue; // Make a first pass over our tasks, finding the // highest-priority item per source. max_priority_by_source.Clear (); foreach (Task task in tasks_by_tag.Values) { if (task.Blocked || task.TriggerTime >= now) continue; if (max_priority_by_source.Contains (task.Source)) { Priority p = (Priority) max_priority_by_source [task.Source]; if (p < task.Priority) max_priority_by_source [task.Source] = task.Priority; } else { max_priority_by_source [task.Source] = task.Priority; } } // Now make a second pass over the tasks and find // the highest-priority item. We use the information // from the first pass to correctly prioritize maintenance tasks. Task next_task = null; foreach (Task task in tasks_by_tag.Values) { if (task.Blocked) continue; if (task.TriggerTime >= now) { if (task.TriggerTime < next_trigger_time) next_trigger_time = task.TriggerTime; continue; } // If this is a maintenance task and there is a high-priority // task from the same source, skip it. if (task.Priority == Priority.Maintenance) { Priority p = (Priority) max_priority_by_source [task.Source]; if (p > task.Priority) continue; } if (task.TriggerTime < now) { if (next_task == null || next_task.CompareTo (task) < 0) next_task = task; } } // If we didn't find a task, wait for the next trigger-time // and then re-start our while loop. if (next_task == null) { if (next_trigger_time == DateTime.MaxValue) { status_str = "Waiting for an unblocked task"; Monitor.Wait (big_lock); } else { status_str = "Waiting for the next trigger time"; Monitor.Wait (big_lock, next_trigger_time - now); } executed_task_count = 0; continue; } // If we did find a task, do we want to execute it right now? // Or should we wait a bit? // How should we space things out? double delay = 0; delay = ComputeDelay (next_task.Priority, duration_of_previous_task, executed_task_count); delay = Math.Min (delay, (next_trigger_time - now).TotalSeconds); if (Debug) Log.Debug ("Computed a delay of {0:.00}s for next task ({1}: {2})", delay, next_task.Tag, next_task.Priority); // Adjust by the time that has actually elapsed since the // last task. delay -= (now - end_time_of_previous_task).TotalSeconds; // If we still need to wait a bit longer, wait for the appropriate // amount of time and then re-start our while loop. if (delay > 0.001) { TimeSpan span = TimeSpanFromSeconds (delay); if (Debug) Log.Debug ("Waiting {0:.00}s until the next task at {1}", span.TotalSeconds, now + span); status_str = String.Format ("Waiting for next task at {0}", now + span); Monitor.Wait (big_lock, span); executed_task_count = 0; continue; } // // If we've made it to this point, it is time to start // executing our selected task. // to_be_executed.Clear (); if (next_task.Collector == null) { to_be_executed.Add (next_task); } else { pre_hook = new Hook (next_task.Collector.PreTaskHook); post_hook = new Hook (next_task.Collector.PostTaskHook); // Find all eligible tasks with the same collector, // and add them to the collection list. now = DateTime.Now; foreach (Task task in tasks_by_tag.Values) if (task != next_task && task.Collector == next_task.Collector && !task.Blocked && task.TriggerTime < now) to_be_executed.Add (task); // Order the tasks from highest to lowest priority. // Our original task will always be the first item // in the resulting array. to_be_executed.Sort (); to_be_executed.Add (next_task); to_be_executed.Reverse (); // Now find how many tasks can be executed before we // exceed the collector's maximum weight. If necessary, // prune the list of tasks. double remaining_weight; remaining_weight = next_task.Collector.GetMaximumWeight (); int i = 0; while (i < to_be_executed.Count && remaining_weight > 0) { Task task; task = to_be_executed [i] as Task; remaining_weight -= task.Weight; ++i; } if (i < to_be_executed.Count) to_be_executed.RemoveRange (i, to_be_executed.Count - i); } // Remove the tasks we are about to execute from our // master list. foreach (Task task in to_be_executed) tasks_by_tag.Remove (task.Tag); // Pulse our lock, in case anyone is waiting for it. Monitor.Pulse (big_lock); } // Now actually execute the set of tasks we found. status_builder.Length = 0; status_builder.Append ("Executing task"); if (to_be_executed.Count > 1) status_builder.Append ('s'); status_builder.Append ('\n'); foreach (Task task in to_be_executed) { task.AppendToStringBuilder (status_builder); status_builder.Append ('\n'); } status_str = status_builder.ToString (); DateTime start_time = DateTime.Now; if (pre_hook != null) { try { pre_hook (); } catch (Exception ex) { Logger.Log.Error (ex, "Caught exception in pre_hook '{0}'", pre_hook); } } foreach (Task task in to_be_executed) { task.DoTask (); ++total_executed_task_count; ++executed_task_count; } if (post_hook != null) { try { post_hook (); } catch (Exception ex) { Logger.Log.Error (ex, "Caught exception in post_hook '{0}'", post_hook); } } end_time_of_previous_task = DateTime.Now; duration_of_previous_task = (end_time_of_previous_task - start_time).TotalSeconds; } // Execute all shutdown tasks foreach (Task task in shutdown_task_queue) if (! task.Cancelled && ! task.Blocked) task.DoTask (); // Call Cleanup on all of our unexecuted tasks foreach (Task task in tasks_by_tag.Values) task.Cleanup (); if (Debug) Logger.Log.Debug ("Scheduler.Worker finished"); }
public TaskGroupPrivate (string name, Hook pre_hook, Hook post_hook) { this.name = name; this.pre_hook = pre_hook; this.post_hook = post_hook; }
////////////////////////////////////////////////////////////////////////////// // // Task Groups // public static TaskGroup NewTaskGroup (string name, Hook pre_hook, Hook post_hook) { return new TaskGroupPrivate (name, pre_hook, post_hook); }