static void HandleComplete(ValkWFStep Step) { string reply = ""; for (int i = 0; i < Step.NextSteps.Count; i++) { ValkWFStep NextStep = Step.NextSteps[i]; if (!NextStep.Skip) { if (NextStep.SyncCount > 1) { UpdateSyncCounts(NextStep); } else { //no waiting! ValkQueueWFMessage WFMessage = new ValkQueueWFMessage(); NextStep.Status = "active"; WFMessage.Command = ValkQueueWFMessage.WFCommand.WFC_ACTIVATE; WFMessage.Step = NextStep; WFMessage.InstanceKey = NextStep.InstanceKey; QueueDBHandlerComm.Send <ValkQueueWFMessage>(WFMessage); reply = QueueDBHandlerComm.Recv(Encoding.Unicode); ActiveSteps.Add(NextStep); } } else { //we may need to update wait counts here //update database ValkQueueWFMessage WFMessage = new ValkQueueWFMessage(); NextStep.Status = "skip"; WFMessage.Step = NextStep; WFMessage.InstanceKey = NextStep.InstanceKey; WFMessage.Command = ValkQueueWFMessage.WFCommand.WFC_SKIP; QueueDBHandlerComm.Send <ValkQueueWFMessage>(WFMessage); reply = QueueDBHandlerComm.Recv(Encoding.Unicode); //TODO: update sync counts of children, recursively, will need to look for new activates as well //probably doesn't need to be recursive because the system will handle it as the children complete //will need to recurse (or re-insert) for children where this is the only parent to set them to skip // use inproc://queueself and create a new message channel to send messages directly back to itself? // --this won't work, because they will wait for (or expect) a reply on the other side, but its one thread } Step.NextSteps[i] = NextStep; } //todo remember to remove from active list for (int i = 0; i < ActiveSteps.Count; i++) { if (ActiveSteps[i].WFTemplateID == Step.WFTemplateID && ActiveSteps[i].WFTemplateStepID == Step.WFTemplateStepID && ActiveSteps[i].InstanceKey == Step.InstanceKey) { ActiveSteps.RemoveAt(i); //step back since the count changed and the next one will be one behind i--; } } }
static void ValkWFActivator_PollInHandler(Socket socket, IOMultiPlex revents) { //handle workflow instantiations ValkQueueWFMessage WFMessage = socket.Recv <ValkQueueWFMessage>(); if (WFMessage.Command == ValkQueueWFMessage.WFCommand.WFC_LOAD) { ValkWFStep NewInstance = null; //Console.WriteLine("Instance Insert Request Received: " + WFMessage.InstanceID + " " + WFMessage.InstanceKey); if (!LoadedInstances.Contains(WFMessage.InstanceID)) { LoadedInstances.Add(WFMessage.InstanceID); SortedDictionary <int, ValkWFStep> ToInsert = new SortedDictionary <int, ValkWFStep>(); dbHandler.StartWFInstance(WFMessage.InstanceID); if (LoadedActiveInstanceByType.ContainsKey(WFMessage.InstanceType)) { NewInstance = LoadedInstanceTemplates[LoadedActiveInstanceByType[WFMessage.InstanceType]].DeepClone <ValkWFStep>(); BuildInsertWFInstance(ToInsert, NewInstance, WFMessage.InstanceKey, true); //Console.WriteLine(DateTime.Now.ToLongTimeString() + ": Created New Instance: " + WFMessage.InstanceKey); } else { //error, no WF of this type found active } if (ToInsert.Count > 0) { InsertWFInstance(ToInsert); ValkQueueWFMessage QueueMessage = new ValkQueueWFMessage(); QueueMessage.InstanceID = WFMessage.InstanceID; QueueMessage.InstanceKey = WFMessage.InstanceKey; QueueMessage.InstanceType = WFMessage.InstanceType; QueueMessage.Command = ValkQueueWFMessage.WFCommand.WFC_ACTIVATE; QueueMessage.Step = NewInstance; QueueComm.Send <ValkQueueWFMessage>(QueueMessage); string reply = QueueComm.Recv(Encoding.Unicode); } socket.Send("OK", Encoding.Unicode); } else { //else don't do anything, duplicate message socket.Send("WARN-Duplicate Request", Encoding.Unicode); } } else { //log error message socket.Send("ERROR-Wrong Request Type", Encoding.Unicode); } }
private static void LoadChildren(ValkWFStep CurrentStep, IDatabaseHandler dbHandler) { List <ValkWFStep> Children = dbHandler.LoadChildSteps(CurrentStep); //do children loading outside, here for (int i = 0; i < Children.Count(); i++) { ValkWFStep substep = Children[i]; LoadChildren(substep, dbHandler); Children[i] = substep; } CurrentStep.NextSteps = Children; }
private static void LoadWorkflowTemplates(IDatabaseHandler dbHandler) { //WorkFlowTemplates //list to store loads to help reduce recursive SQL queries WFTemplateLoadingData loadingData = dbHandler.LoadWFTemplates(); LoadedActiveInstanceByType = loadingData.LoadedActiveInstanceByType; for (int i = 0; i < loadingData.WFsToLoad.Count(); i++) { ValkWFStep CurrentStep = loadingData.WFsToLoad[i]; LoadChildren(CurrentStep, dbHandler); loadingData.WFsToLoad[i] = CurrentStep; LoadedInstanceTemplates[loadingData.WFsToLoad[i].WFTemplateID] = loadingData.WFsToLoad[i]; } Console.WriteLine("Workflows Loaded"); }
/// <summary> /// utility function to determine if this step currently has any sync counts /// </summary> /// <param name="Step"></param> /// <returns></returns> static bool SyncWaitExists(ValkWFStep Step) { bool Exists = false; if (StepsWithSyncWait.ContainsKey(Step.WFTemplateID)) { if (StepsWithSyncWait[Step.WFTemplateID].ContainsKey(Step.WFTemplateStepID)) { if (StepsWithSyncWait[Step.WFTemplateID][Step.WFTemplateStepID].ContainsKey(Step.InstanceKey)) { Exists = true; } } } return(Exists); }
/// <summary> /// Creates all child-steps of a workflow instance (recursively) so that the entire flow can be inserted /// prior to being set active. /// </summary> /// <param name="ToInsert"></param> /// <param name="Step"></param> /// <param name="InstanceID"></param> /// <param name="insert"></param> static void BuildInsertWFInstance(SortedDictionary <int, ValkWFStep> ToInsert, ValkWFStep Step, string InstanceID, bool insert) { Step.InstanceKey = InstanceID; if (insert && !ToInsert.ContainsKey(Step.WFTemplateStepID)) { ToInsert[Step.WFTemplateStepID] = Step; } else { insert = false; } for (int i = 0; i < Step.NextSteps.Count; i++) { ValkWFStep substep = Step.NextSteps[i]; BuildInsertWFInstance(ToInsert, substep, InstanceID, insert); Step.NextSteps[i] = substep; } }
/// <summary> /// Steps can be programatically skipped (not all paths in a workflow are followed) /// This function updates the synccount of any children to include the skipped /// step as "complete" /// </summary> /// <param name="Step">Step being skipped</param> static void UpdateSkip(ref ValkWFStep Step) { for (int i = 0; i < Step.NextSteps.Count; i++) { ValkWFStep substep = Step.NextSteps[i]; substep.SyncCount--; if (substep.SyncCount == 0) { substep.Skip = true; UpdateSkip(ref substep); } else { UpdateSyncCounts(substep); } Step.NextSteps[i] = substep; } }
static void UpdateSyncCounts(ValkWFStep NextStep) { string reply = ""; NextStep.SyncCount--; //TODO: update sync count in the DB if (SyncWaitExists(NextStep)) { StepsWithSyncWait[NextStep.WFTemplateID][NextStep.WFTemplateStepID][NextStep.InstanceKey].SyncCount--; //if we're no longer waiting, set this step to active if (StepsWithSyncWait[NextStep.WFTemplateID][NextStep.WFTemplateStepID][NextStep.InstanceKey].SyncCount <= 0) { ValkQueueWFMessage WFMessage = new ValkQueueWFMessage(); NextStep.Status = "active"; WFMessage.Command = ValkQueueWFMessage.WFCommand.WFC_ACTIVATE; WFMessage.Step = NextStep; WFMessage.InstanceKey = NextStep.InstanceKey; QueueDBHandlerComm.Send <ValkQueueWFMessage>(WFMessage); reply = QueueDBHandlerComm.Recv(Encoding.Unicode); ActiveSteps.Add(NextStep); } } else { if (!StepsWithSyncWait.ContainsKey(NextStep.WFTemplateID)) { StepsWithSyncWait[NextStep.WFTemplateID] = new SortedDictionary <int, SortedDictionary <string, ValkWFStep> >(); } if (!StepsWithSyncWait[NextStep.WFTemplateID].ContainsKey(NextStep.WFTemplateStepID)) { StepsWithSyncWait[NextStep.WFTemplateID][NextStep.WFTemplateStepID] = new SortedDictionary <string, ValkWFStep>(); } StepsWithSyncWait[NextStep.WFTemplateID][NextStep.WFTemplateStepID][NextStep.InstanceKey] = NextStep.DeepClone(); StepsWithSyncWait[NextStep.WFTemplateID][NextStep.WFTemplateStepID][NextStep.InstanceKey].SyncCount--; } }