/// <summary> /// Execute a process transaction /// Warning: you need to execute this method inside a Transaction (TransactionScope) /// this is how you control if the changes will be saved to the db. /// @param persMode - persistence mode /// /// assume we have all process tasks in a single record /// so when performing modification, we need to limit our scope to that record (this process instance) /// and all messages leaving the process will be handled async /// so we divide our messages between in-process and inter-process /// inter-process are always async /// in-process are sync when they're task control messages /// async when they are from send/receive message tasks (hmmm, this doesn't really matter when in proc) /// /// what about transactions? /// - we assume we're already inside a system transaction /// - we can get an external db connection. If we don't get it, we need to open it. /// - process session /// - other components should have an option to be notified about commit - use system.transactions api... /// </summary> public void RunProcessTransaction(TaskPersistenceMode persMode, Action <ProcessSession> act) { if (ProcessSession.Current != null) { act(ProcessSession.Current); return; } Queue <ProcessMessage> outgoing = null; InSystemTransaction(() => { InDbTransaction(SessionFactory, dbs => { var pess = TaskPersister.OpenSession(dbs); pess.PersistenceMode = persMode; var ps = new ProcessSession(pess, MessageBus, ServiceResolver); try { ProcessSession.Current = ps; ps.MessageBus = MessageBus; ps.TaskPersister = pess; act(ps); PumpMessages(ps); outgoing = ps.AsyncQueue; } finally { ProcessSession.Current = null; ps.Dispose(); } pess.SaveChanges(); pess.Dispose(); }); }); if (outgoing != null) { foreach (var pm in outgoing) { SendLocalAsyncMessage(pm); } } }
protected void PumpMessages(ProcessSession ps) { var queue = ps.SyncQueue; while (queue.Count > 0) { var m = queue.Dequeue(); if (m is TaskExecEvent) { var te = m as TaskExecEvent; if (te.FromTaskInstanceId == te.FromProcessInstanceId || InstanceId.IsSameProcessInstance(te.ParentTaskInstanceId, te.FromProcessInstanceId)) { DeliverTaskExecEvent(te); } else { MessageBus.Notify(te); } } else if (m is TaskControlCommand) { var tc = m as TaskControlCommand; if (InstanceId.IsSameProcessInstance(tc.FromProcessInstanceId, tc.ToTaskInstanceId)) { DeliverTaskControlMessage(tc); } else { MessageBus.Notify(tc); } } else { throw new Exception("Unexpected message in queue"); } } }