/// <summary> /// Swap out the existing dispatch in scheduling pool with the dispatch set for callback /// This is called when a tool calls back the engine to run at a later time /// </summary> /// <param name="IRQ"></param> internal static void RelocateCallbackDispatch(IrqHandle IRQ) { SchedulingHandle schedulinghandle; Dispatch olddispatch; Dispatch currentdispatch; Int64 scheduleid = IRQ.ScheduleID; Int64? olddispatchid = IRQ.DispatchID; DateTime currentdatetimeutc = DateTime.UtcNow; using (DispatchEngineContainer dec = new DispatchEngineContainer()) { // reset the retry & error fields of the old dispatch olddispatch = dec.Dispatches.Single(d => d.Id == olddispatchid); olddispatch.RetryCount = 0; olddispatch.ErrorCode = null; olddispatch.ErrorMsg = null; olddispatch.LastModifiedDateTimeUtc = currentdatetimeutc; olddispatch.StatusID = DispatchStatus.Pending; if (dec.SchedulingPool.Any(sh => sh.ScheduleID == scheduleid)) { // double check to make sure current DispatchID in scheduling pool // is NOT the same as the callback DispatchID if (dec.SchedulingPool.Any(sh => sh.DispatchID != olddispatch.Id)) { schedulinghandle = dec.SchedulingPool.Single(dh => dh.ScheduleID == scheduleid); // set the current dispatch to cancelled currentdispatch = dec.Dispatches.Single(d => d.Id == schedulinghandle.DispatchID); currentdispatch.LastModifiedDateTimeUtc = currentdatetimeutc; currentdispatch.StatusID = DispatchStatus.Cancelled; // swap the current dispatch out with the old one schedulinghandle.DispatchID = (long)olddispatchid; } } else { schedulinghandle = new SchedulingHandle() { ScheduleID = scheduleid, DispatchID = (long)olddispatchid }; dec.SchedulingPool.Add(schedulinghandle); } // remove current interrupt dec.IrqQueue.Attach(IRQ); dec.IrqQueue.Remove(IRQ); dec.SaveChanges(); } }
/// <summary> /// Create a new Dispatch and add to scheduling pool for new schedules. Otherwise swap existing dispatch out /// This is called after a schedule change or dispatch has completed /// </summary> /// <param name="ScheduleID"></param> internal static void PlanSchedulingPool(DpcHandle DPC) { SchedulingHandle schedulinghandle; Dispatch olddispatch; Dispatch newdispatch; Schedule schedule; Tool tool; CallbackDevice callbackdevice; bool inschedulingpool; DateTime nextdispatchdatetimeutc; DateTime currentdatetimeutc = DateTime.UtcNow; using (DispatchEngineContainer dec = new DispatchEngineContainer()) { schedule = dec.Schedules.Single(s => s.Id == DPC.ScheduleID); dec.Entry(schedule).Reference(r => r.Tool).Load(); // current implementation only supports one tool per schedule tool = schedule.Tool; nextdispatchdatetimeutc = GetTargetDispatchDateTimeUtc(schedule); newdispatch = new Dispatch() { CreatedDateTimeUtc = currentdatetimeutc, LastModifiedDateTimeUtc = currentdatetimeutc, StatusID = DispatchStatus.Pending, RetryCount = 0, ScheduleID = DPC.ScheduleID, StartDateTimeUtc = nextdispatchdatetimeutc, ToolID = schedule.Tool.Id }; // new schedule will not have a dispatch in pool inschedulingpool = dec.SchedulingPool.Any(dh => dh.ScheduleID == DPC.ScheduleID); if (inschedulingpool) { // check if dispatch is waiting for callback // there should always be a dispatch in pool if this is not a new schedule olddispatch = dec.Dispatches.Single(dh => dh.Id == DPC.DispatchID); if (olddispatch.StatusID != DispatchStatus.Callback) { schedulinghandle = dec.SchedulingPool.Single(dh => dh.ScheduleID == DPC.ScheduleID); // set old dispatch to cancel only if it is in pending status if (olddispatch.StatusID == DispatchStatus.Pending) { olddispatch.StatusID = DispatchStatus.Cancelled; olddispatch.LastModifiedDateTimeUtc = currentdatetimeutc; } // swap out old dispatch if schedule is dispatchable if (schedule.EndDateTimeUtc > nextdispatchdatetimeutc) { dec.Dispatches.Add(newdispatch); dec.SaveChanges(); dec.Entry(newdispatch).Reload(); schedulinghandle.DispatchID = newdispatch.Id; } } } else { // this case it is a new schedule, we need to add to the schedule pool as well dec.Dispatches.Add(newdispatch); dec.SaveChanges(); dec.Entry(newdispatch).Reload(); // add devices associated to schedule to CallbackDevices table that is specifically maintained by engine dec.Entry(schedule).Collection(c => c.Devices).Load(); if (schedule.Devices.Count > 0) { foreach (var device in schedule.Devices) { callbackdevice = new CallbackDevice() { DispatchID = newdispatch.Id, DeviceID = device.Id }; dec.CallbackDevices.Add(callbackdevice); } } schedulinghandle = new SchedulingHandle() { ScheduleID = DPC.ScheduleID, DispatchID = newdispatch.Id }; dec.SchedulingPool.Add(schedulinghandle); } // remove current DPC dec.DpcQueue.Attach(DPC); dec.DpcQueue.Remove(DPC); dec.SaveChanges(); } }