static ValkQueueWFMessage GetNextStep(ValkQueueWFMessage WFMessage) { ValkQueueWFMessage ReplyMessage = new ValkQueueWFMessage(); ReplyMessage.Command = ValkQueueWFMessage.WFCommand.WFC_WAIT; bool stepfound = false; int i = 0; //cycle through all of our current steps until we find an active one //todo: provide an actual queue of active steps so we don't have to go searching // we should be adding to "active" as they come in, and moving to a list for "pending" // once processing starts while (stepfound == false && i < ActiveSteps.Count) { if (ActiveSteps[i].Status == "active") { ActiveSteps[i].Status = "pending"; ReplyMessage.Step = ActiveSteps[i].DeepClone(); ReplyMessage.InstanceKey = ReplyMessage.Step.InstanceKey; ReplyMessage.Command = ValkQueueWFMessage.WFCommand.WFC_LOAD; stepfound = true; } i++; } return(ReplyMessage); }
/// <summary> /// Control function for this class so we can gracefully startup/pause/exit the entire system /// </summary> /// <param name="socket"></param> /// <param name="revents"></param> static void ValkQueueWFStepsCTRL_PollInHandler(Socket socket, IOMultiPlex revents) { string Message = socket.Recv(Encoding.Unicode); Console.WriteLine(Message); if (Message == "GO") { Stop = false; } else if (Message == "STOP") { Stop = true; } else if (Message == "EXIT") { ValkQueueWFMessage ExitMessage = new ValkQueueWFMessage(); ExitMessage.Command = ValkQueueWFMessage.WFCommand.WFC_EXIT; QueueDBHandlerComm.Send <ValkQueueWFMessage>(ExitMessage); string mesg = QueueDBHandlerComm.Recv(Encoding.Unicode); DBHandler.Join(); Stop = true; Exit = true; } socket.Send("OK:" + Message, Encoding.Unicode); }
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 ValkQueueWFSteps_PollInHandler(Socket socket, IOMultiPlex revents) { string reply = ""; ValkQueueWFMessage WFMessage = socket.Recv <ValkQueueWFMessage>(); switch (WFMessage.Command) { case ValkQueueWFMessage.WFCommand.WFC_WAIT: //great, don't do anything, probably a warning socket.Send("OK", Encoding.Unicode); break; case ValkQueueWFMessage.WFCommand.WFC_LOAD: //warning, we don't handle this socket.Send("OK", Encoding.Unicode); break; case ValkQueueWFMessage.WFCommand.WFC_CANPROCESS: //this will be a big one... socket.Send <ValkQueueWFMessage>(GetNextStep(WFMessage)); break; case ValkQueueWFMessage.WFCommand.WFC_ACTIVATE: //set first step to active, insert neededness WFMessage.Step.Status = "active"; QueueDBHandlerComm.Send <ValkQueueWFMessage>(WFMessage); reply = QueueDBHandlerComm.Recv(Encoding.Unicode); socket.Send("OK", Encoding.Unicode); ActiveSteps.Add(WFMessage.Step); break; case ValkQueueWFMessage.WFCommand.WFC_COMPLETE: //should also try to pick up the next step here, no reason to waste cycles WFMessage.Step.Status = "complete"; QueueDBHandlerComm.Send <ValkQueueWFMessage>(WFMessage); reply = QueueDBHandlerComm.Recv(Encoding.Unicode); HandleComplete(WFMessage.Step); ValkQueueWFMessage NewMessage = new ValkQueueWFMessage(); NewMessage.Command = ValkQueueWFMessage.WFCommand.WFC_CANPROCESS; socket.Send <ValkQueueWFMessage>(GetNextStep(NewMessage)); break; case ValkQueueWFMessage.WFCommand.WFC_EXCEPTION: break; case ValkQueueWFMessage.WFCommand.WFC_STOP: socket.Send("OK", Encoding.Unicode); break; case ValkQueueWFMessage.WFCommand.WFC_SUBFLOW: socket.Send("OK", Encoding.Unicode); break; default: break; } }
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); } }
//public void Initialize() //{ // Thread Processor; // Processor = new Thread(new ThreadStart(ValkQueueWFSteps.RunQueue)); // Processor.Start(); //} public static void RunProcessor() { if (QueueContext == null) { QueueContext = new Context(1); } //throw new System.Exception("QueueContext not set"); QueueComm = QueueContext.Socket(SocketType.REQ); QueueComm.Connect("tcp://127.0.0.1:5000"); /* * ActivatorIntraComm.Bind("tcp://*:5001"); * ActivatorControllerIntraComm = ActContext.Socket(SocketType.REP); * ActivatorControllerIntraComm.Connect("inproc://activatorcontrol"); * QueueComm = ActContext.Socket(SocketType.REQ); * QueueComm.Connect("tcp://127.0.0.1:5000"); * */ ValkQueueWFMessage WFMessage = new ValkQueueWFMessage(); WFMessage.Command = ValkQueueWFMessage.WFCommand.WFC_CANPROCESS; while (true) { try { //Thread.Sleep(10000); QueueComm.Send <ValkQueueWFMessage>(WFMessage); WFMessage = QueueComm.Recv <ValkQueueWFMessage>(); } catch (ZMQ.Exception ex) { Console.WriteLine(ex.Message); } if (WFMessage.Command == ValkQueueWFMessage.WFCommand.WFC_WAIT) { Thread.Sleep(5000); WFMessage.Command = ValkQueueWFMessage.WFCommand.WFC_CANPROCESS; } else { if (WFMessage.Command != ValkQueueWFMessage.WFCommand.WFC_CANPROCESS) { ProcessData(ref WFMessage); } } } }
public static void ProcessData(ref ValkQueueWFMessage WFMessage) { //default, automatically complete everything if (StepHandlers.ContainsKey(WFMessage.Step.HandleCategory)) { StepHandlers[WFMessage.Step.HandleCategory].HandleStep(ref WFMessage); } else { if (DefaultHandler == null) { Console.WriteLine("No handler for " + WFMessage.Step.HandleCategory + " and no default provided"); } else { DefaultHandler.HandleStep(ref WFMessage); } } }
public static void StartPolling(IDatabaseHandler dbHandler) { if (PollContext == null) { throw new System.Exception("PollContext not set"); } // Prepare our sockets PollerControlIntraComm = PollContext.Socket(SocketType.REP); PollerControlIntraComm.Connect("inproc://pollercontrol"); ActivatorIntraComm = PollContext.Socket(SocketType.REQ); ActivatorIntraComm.Connect("inproc://activator"); PollItem[] Poller = new PollItem[1]; Poller[0] = PollerControlIntraComm.CreatePollItem(IOMultiPlex.POLLIN); Poller[0].PollInHandler += new PollHandler(PollerCTRL_PollInHandler); while (!Exit) { PollContext.Poll(Poller, 5000); if (!Stop) { //poll //get all available pending workflow instances DataTable dt = dbHandler.GetPendingWFInstances(); foreach (DataRow Row in dt.Rows) { //send to kickoff ValkQueueWFMessage Message = new ValkQueueWFMessage(); Message.Command = ValkQueueWFMessage.WFCommand.WFC_LOAD; Message.InstanceID = int.Parse(Row["WFInstanceID"].ToString()); Message.InstanceKey = Row["InstanceKey"].ToString(); Message.InstanceType = Row["WFType"].ToString(); ActivatorIntraComm.Send <ValkQueueWFMessage>(Message); string message = ActivatorIntraComm.Recv(Encoding.Unicode); //Console.WriteLine("Instance Insert Reply Received: " + message); } } } }
static void ValkQueueDBHandler_PollInHandler(Socket socket, IOMultiPlex revents) { ValkQueueWFMessage WFMessage = socket.Recv <ValkQueueWFMessage>(); switch (WFMessage.Command) { case ValkQueueWFMessage.WFCommand.WFC_EXIT: socket.Send("OK", Encoding.Unicode); Exit = true; break; case ValkQueueWFMessage.WFCommand.WFC_ACTIVATE: StepsToUpdate.Add(WFMessage); socket.Send("OK", Encoding.Unicode); break; case ValkQueueWFMessage.WFCommand.WFC_COMPLETE: StepsToUpdate.Add(WFMessage); socket.Send("OK", Encoding.Unicode); break; case ValkQueueWFMessage.WFCommand.WFC_SKIP: StepsToUpdate.Add(WFMessage); socket.Send("OK", Encoding.Unicode); break; case ValkQueueWFMessage.WFCommand.WFC_EXCEPTION: break; case ValkQueueWFMessage.WFCommand.WFC_STOP: break; case ValkQueueWFMessage.WFCommand.WFC_SUBFLOW: break; default: break; } }
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--; } }