void IWaitingResumptionHandle.Resume(WaitingResumption waitingResumption)
        {
            var r = waitingResumption as SubProcessCompleteResumption;
            var subProcess = r.SubProcess;
            var parentProcess = r.Process;

            //尝试从父流程中获取启动该子流程的节点实例信息
            SubProcessActivityInstance sub = this._processService.GetSubProcessActivityInstances(parentProcess, subProcess);
            if (sub == null)
                throw new InvalidOperationException(string.Format("没有在父流程“{0}”#{1}中找到启动子流程“{2}”#{3}的子流程节点实例"
                    , parentProcess.Title
                    , parentProcess.ID
                    , subProcess.Title
                    , subProcess.ID));
            //将子流程的流程变量传递给父流程
            var dict = subProcess.GetDataFields();
            foreach (string key in dict.Keys)
                parentProcess.UpdateDataField(key, dict[key]);
            //唤醒父流程
            var persisted = this._processService.GetWorkflowInstance(parentProcess).WorkflowInstance;
            var instance = WorkflowBuilder.CreateInstance(parentProcess, this._parser);
            instance.Load(persisted);
            instance.Update(parentProcess.GetInputs());
            instance.ResumeBookmark(sub.ReferredBookmarkName, null);
            //目前不允许在调度项中生成新的非延迟调度项,无法保证预期顺序,需要有类似核心的quack机制
            ////创建父流程唤醒调度项
            //this._resumption.Add(new BookmarkResumption(parentProcess
            //    , sub.ActivityName
            //    , sub.ReferredBookmarkName
            //    , string.Empty));

            //将子流程节点置为完成
            sub.SetAsComplete();
            this._processService.UpdateActivityInstance(sub);
        }
        void IWaitingResumptionHandle.Resume(WaitingResumption waitingResumption)
        {
            var r = waitingResumption as ActivityInstanceCancelResumption;

            try
            {
                //由于该调度项是允许自动重试的,应避免无关异常产生影响调度队列
                if (r != null
                    && r.Process != null
                    && r.ActivityInstance != null)
                    this._processService.CancelAllAbout(r.Process, r.ActivityInstance);
            }
            catch (Exception e)
            {
                this._log.Warn("取消流程节点实例时异常,将自动重试", e);
                throw e;
            }
        }
        void IWaitingResumptionHandle.Resume(WaitingResumption waitingResumption)
        {
            var r = waitingResumption as HumanEscalationResumption;
            var process = r.Process;
            var activityName = r.HumanActivityInstance.ActivityName;
            var setting = process.ProcessType.GetHumanSetting(activityName);
            var workItems = this._workItemService.GetWorkItems(process, activityName);
            HumanEscalationRule rule = setting.EscalationRule;
            IDictionary<string, string> dataFields = process.GetDataFields();

            if (rule == null
                || !rule.IsValid
                || workItems.Count() == 0)
            {
                this._log.WarnFormat("流程“{0}”#{1}的节点“{2}”的超时事件升级规则无效或已经失效"
                    , process.Title
                    , process.ID
                    , r.HumanActivityInstance.ActivityName);
                return;
            }
            string to;
            if (rule.NotifyTemplateName != null)
            {
                //消息通知
                this._helper.Notify(process, workItems, rule.NotifyTemplateName);
                //重复通知
                if (rule.NotifyRepeatMinutes.HasValue)
                {
                    //从当前开始计算
                    var at = DateTime.Now.AddMinutes(rule.NotifyRepeatMinutes.Value);
                    this._schedulerService.Add(new HumanEscalationResumption(r.Process, at, r.HumanActivityInstance));
                    this._log.InfoFormat("由于设置了重复通知,再次创建超时事件升级调度项,将于{0}激活", at);
                }
            }
            else if (!string.IsNullOrEmpty(rule.RedirectTo)
                //HACK:【脚本使用】解析脚本获取实际转交目标
                && !string.IsNullOrWhiteSpace(to = this.Evaluate(rule.RedirectTo, process)))
                //将当前任务转交给其他人
                this._helper.Redirect(process, activityName, workItems, to);
            else if (!string.IsNullOrEmpty(rule.GotoActivityName))
                //强制跳转到指定节点
                this._helper.Goto(process, activityName, rule.GotoActivityName);
        }
Exemplo n.º 4
0
        void IWaitingResumptionHandle.Resume(WaitingResumption waitingResumption)
        {
            try
            {
                var r = waitingResumption as ErrorResumption;
                //错误恢复使用粗粒度实现,不延续原有工作流实例树
                var instance = WorkflowBuilder.CreateInstance(r.Process, this._parser);
                instance.Update(r.Process.GetInputs());
                instance.Run();

                this._log.InfoFormat("尝试对流程{0}#{1}在FlowNodeIndex={2}处进行了错误恢复"
                    , r.Process.Title
                    , r.Process.ID
                    , r.ErrorNodeIndex);
            }
            catch (Exception e)
            {
                //由于ErrorResumption本身就是错误恢复调度,即使异常也不应抛出而导致其本身被记录成error
                this._log.Error("错误重试时异常", e);
            }
        }
            void ISchedulerService.Add(WaitingResumption r)
            {

            }
 void ISchedulerService.MarkAsError(WaitingResumption r)
 {
     _resumCount += 1;
 }
Exemplo n.º 7
0
        public void Resume(WaitingResumption r)
        {
            if (r == null)
            {
                throw new InvalidOperationException("无效的恢复请求");
            }

            //HACK:时间调度有可能导致调度器被未满足请求占满,需要在ChargeResumption时预先进行过滤,在db处理
            if (!r.CanResumeAtNow)
            {
                if (this._log.IsDebugEnabled)
                {
                    this._log.Debug("当前时间未满足恢复时间条件");
                }
                return;
            }

            if (!r.CanExecuting)
            {
                r.SetInvalid();
                _repository.Update(r);
                this._log.WarnFormat("流程{0}#{1}处于{2}状态,该调度请求不允许被执行,取消该调度请求{3}#{4}"
                                     , r.Process.Title
                                     , r.Process.ID
                                     , r.Process.Status
                                     , r
                                     , r.ID);
                return;
            }

            var success = false;

            //TODO:是否需要并将流程置为Error状态?
            //恢复调度中的任何异常都不能影响调度过程,同时间调度的考虑一样,无法被执行调度也有可能堆积而影响调度
            try
            {
                DependencyResolver.Resolve <IWaitingResumptionHandle>(r.Handle).Resume(r);
                success = true;
                this._log.InfoFormat("[调度记录]{0}#{1}|Priority={2}|ProcessType={3}|ProcessId={4}"
                                     , r
                                     , r.ID
                                     , r.Priority
                                     , r.Process.ProcessType.Name
                                     , r.Process.ID);
            }
            catch (Exception e)
            {
                //TODO:将流程置为Error,此处异常通常是系统异常
                this._log.Error(string.Format("Resumption Error Occur At {0}#{1}", r, r.ID), e);
            }
            finally
            {
                //若允许重试,则可以继续被调度,要考虑重试堆积问题,可通过引入调度优先级来避免
                if (success || !r.EnableRetry)
                {
                    //将调度请求完成后置为失效
                    r.SetExecuted();
                    _repository.Update(r);
                }
            }
        }
Exemplo n.º 8
0
 void ISchedulerService.MarkAsError(WaitingResumption r)
 {
     _resumCount += 1;
 }
Exemplo n.º 9
0
 void ISchedulerService.Add(WaitingResumption r)
 {
 }
Exemplo n.º 10
0
        public virtual void Resume(WaitingResumption r)
        {
            //HACK:【重要】时间调度有可能导致调度器被未满足请求占满,必须在repository层ChargeResumption时预先进行过滤
            if (!r.CanResumeAtNow)
            {
                if (this._log.IsDebugEnabled)
                    this._log.Debug("当前时间未满足延迟调度项的时间条件");
                return;
            }
            /* 
             * HACK:【重要】将处于不可执行的调度项置为无效,用于处理由于以下原因出现的不合法的调度记录:
             * 流程状态与调度状态发生冲突,不过此类情况已经在调度重构后最大限度避免,但由于调度/服务分离的方式,还是保留此逻辑避免意外
             */
            if (!r.CanExecuting)
            {
                r.SetInvalid();
                this._resumptionService.Update(r);
                this._log.WarnFormat("流程{0}#{1}处于{2}状态,该调度请求不允许被执行,取消该调度请求{3}#{4}"
                    , r.Process.Title
                    , r.Process.ID
                    , r.Process.Status
                    , r
                    , r.ID);
                return;
            }
            //通过调度项对应的执行器执行实际调度逻辑
            DependencyResolver.Resolve<IWaitingResumptionHandle>(r.Handle).Resume(r);
            //尝试将流程置为Active状态
            this.TrySetAsActiveAtResumption(r.Process, r);//注意与Update(r)的先后顺序,避免二者逻辑(update与AnyValidAndUnExecutedResumptions)死锁
            //置为已执行
            r.SetExecuted();
            this._resumptionService.Update(r);

            this._log.InfoFormat(
                "[调度记录]{0}#{1}|Priority={2}|ProcessTitle={3}|ProcessId={4}"
                , r
                , r.ID
                , r.Priority
                , r.Process.Title
                , r.Process.ID);
        }
Exemplo n.º 11
0
 private void AssertExecutedResumption(WaitingResumption r)
 {
     Assert.IsTrue(r.IsExecuted);
     Assert.IsFalse(r.IsValid);
 }
Exemplo n.º 12
0
        public void Create()
        {
            var process    = this.Prepare();
            var subProcess = this.PrepareSubProcess(process);

            //流程发起调度
            WaitingResumption r = new ProcessStartResumption(process);

            this._resumptionService.Add(r);
            this.Evict(r);
            WaitingResumption r2 = this._resumptionService.Get(r.ID);

            Assert.IsNotNull(r2);
            Assert.IsInstanceOf <ProcessStartResumption>(r2);
            //书签恢复调度
            r = new BookmarkResumption(process, "节点1", "bookmark", "result");
            this._resumptionService.Add(r);
            this.Evict(r);
            r2 = this._resumptionService.Get(r.ID);
            Assert.IsNotNull(r2);
            Assert.IsInstanceOf <BookmarkResumption>(r2);
            //错误恢复调度
            r = new ErrorResumption(process, 0);
            this._resumptionService.Add(r);
            this.Evict(r);
            r2 = this._resumptionService.Get(r.ID);
            Assert.IsNotNull(r2);
            Assert.IsInstanceOf <ErrorResumption>(r2);
            //人工任务创建调度
            var h = new HumanActivityInstance(process.ID, 0, 1, "节点", "bookmark", new string[] { "houkun" });

            this._processService.CreateActivityInstance(h);
            r = new WorkItemCreateResumption(process, h);
            this._resumptionService.Add(r);
            this.Evict(r);
            r2 = this._resumptionService.Get(r.ID);
            Assert.IsNotNull(r2);
            Assert.IsInstanceOf <WorkItemCreateResumption>(r2);
            //流程完成调度
            TestHelper.ChangeProcessStatus(subProcess, ProcessStatus.Completed);
            r = new SubProcessCompleteResumption(process, subProcess);
            this._resumptionService.Add(r);
            this.Evict(r);
            r2 = this._resumptionService.Get(r.ID);
            Assert.IsNotNull(r2);
            Assert.IsInstanceOf <SubProcessCompleteResumption>(r2);
            //子流程启动调度
            var sub = new SubProcessActivityInstance(process.ID, 0, 1, "节点", "bookmark");

            this._processService.CreateActivityInstance(sub);
            r = new SubProcessCreateResumption(process, sub);
            this._resumptionService.Add(r);
            this.Evict(r);
            r2 = this._resumptionService.Get(r.ID);
            Assert.IsNotNull(r2);
            Assert.IsInstanceOf <SubProcessCreateResumption>(r2);
            //节点实例取消调度
            r = new ActivityInstanceCancelResumption(process, h);
            this._resumptionService.Add(r);
            this.Evict(r);
            r2 = this._resumptionService.Get(r.ID);
            Assert.IsNotNull(r2);
            Assert.IsInstanceOf <ActivityInstanceCancelResumption>(r2);
        }
Exemplo n.º 13
0
 private bool AreAtSameFlowNodeIndex(WaitingResumption prev, WaitingResumption r)
 {
     return !prev.FlowNodeIndex.HasValue
         || !r.FlowNodeIndex.HasValue
         || (prev.FlowNodeIndex.HasValue
         && r.FlowNodeIndex.HasValue
         && r.FlowNodeIndex == prev.FlowNodeIndex);
 }
Exemplo n.º 14
0
 private void TrySetAsActiveAtResumption(Process process, WaitingResumption resumption)
 {
     //只有部分调度项完成后才可进入Active
     if (!resumption.EnableActiveAfterExecuted) return;
     //HACK:【重要】只要存在未执行的有效调度项就不可进入Active状态
     if (this._resumptionService.AnyValidAndUnExecutedResumptions(process, resumption))
     {
         this._log.InfoFormat("由于流程存在未完成的调度请求,无法将其置为Active状态");
         return;
     }
     process.MarkAsActive();
     this._processService.Update(process);
     this._log.InfoFormat("流程实例“{0}”#{1}进入Active状态", process.Title, process.ID);
 }
Exemplo n.º 15
0
 protected virtual void MakeAnError(WaitingResumption r, Exception e)
 {
     //HACK:【重要】此处必须保证更新被提交,不能被nhsession问题影响,因此必须直接sqlupdate来保证
     //r.SetError(true);
     //this._resumptionService.Update(r);
     this._resumptionService.MarkAsError(r);
     this._resumptionService.AddErrorRecord(new FaultResumptionRecord(r.Process, e, r.ID));
 }
Exemplo n.º 16
0
 void IWaitingResumptionHandle.Resume(WaitingResumption waitingResumption)
 {
     var r = waitingResumption as ProcessStartResumption;
     var instance = WorkflowBuilder.CreateInstance(r.Process, this._parser);
     instance.Run();
 }
Exemplo n.º 17
0
        void IWaitingResumptionHandle.Resume(WaitingResumption waitingResumption)
        {
            var r = waitingResumption as WorkItemCreateResumption;
            var human = r.HumanActivityInstance;

            if (human == null)
            {
                this._log.Warn("不存在待创建任务的人工节点信息");
                return;
            }

            var process = r.Process;
            var setting = process.ProcessType.GetHumanSetting(human.ActivityName);

            if (setting == null)
                throw new InvalidOperationException("没有找到节点"
                    + human.ActivityName
                    + "对应的HumanSetting,可能需要修正流程");

            //OneAtOnce依次创建
            if (setting.SlotMode == HumanSetting.SlotDistributionMode.OneAtOnce)
                this._workItemService.Create(human.CreateNextWorkItem(process, this._userService));
            else
            {
                //AllAtOnce一次性创建
                var list = human.CreateAllWorkItem(process, this._userService);
                foreach (var w in list)
                    this._workItemService.Create(w);
            }
            //更新节点实例
            this._processService.UpdateActivityInstance(human);
        }
Exemplo n.º 18
0
        public void Resume(WaitingResumption r)
        {
            if (r == null)
                throw new InvalidOperationException("无效的恢复请求");

            //HACK:时间调度有可能导致调度器被未满足请求占满,需要在ChargeResumption时预先进行过滤,在db处理
            if (!r.CanResumeAtNow)
            {
                if (this._log.IsDebugEnabled)
                    this._log.Debug("当前时间未满足恢复时间条件");
                return;
            }

            if (!r.CanExecuting)
            {
                r.SetInvalid();
                _repository.Update(r);
                this._log.WarnFormat("流程{0}#{1}处于{2}状态,该调度请求不允许被执行,取消该调度请求{3}#{4}"
                    , r.Process.Title
                    , r.Process.ID
                    , r.Process.Status
                    , r
                    , r.ID);
                return;
            }

            var success = false;
            //TODO:是否需要并将流程置为Error状态?
            //恢复调度中的任何异常都不能影响调度过程,同时间调度的考虑一样,无法被执行调度也有可能堆积而影响调度
            try
            {
                DependencyResolver.Resolve<IWaitingResumptionHandle>(r.Handle).Resume(r);
                success = true;
                this._log.InfoFormat("[调度记录]{0}#{1}|Priority={2}|ProcessType={3}|ProcessId={4}"
                    , r
                    , r.ID
                    , r.Priority
                    , r.Process.ProcessType.Name
                    , r.Process.ID);
            }
            catch (Exception e)
            {
                //TODO:将流程置为Error,此处异常通常是系统异常
                this._log.Error(string.Format("Resumption Error Occur At {0}#{1}", r, r.ID), e);
            }
            finally
            {
                //若允许重试,则可以继续被调度,要考虑重试堆积问题,可通过引入调度优先级来避免
                if (success || !r.EnableRetry)
                {
                    //将调度请求完成后置为失效
                    r.SetExecuted();
                    _repository.Update(r);
                }
            }
        }
        void IWaitingResumptionHandle.Resume(WaitingResumption waitingResumption)
        {
            var r = waitingResumption as SubProcessCreateResumption;
            var sub = r.SubProcessActivityInstance;

            if (sub == null)
            {
                this._log.Warn("不存在待创建子流程的子流程节点信息");
                return;
            }

            var parent = r.Process;
            var setting = parent.ProcessType.GetSubProcessSetting(sub.ActivityName);
            if (setting == null)
                throw new InvalidOperationException(string.Format(
                    "没有找到节点“{0}”对应的SubProcessSetting,可能需要修正流程"
                    , sub.ActivityName));
            //更新子流程节点实例
            var subProcessId = Guid.NewGuid();
            sub.SetSubProcessId(subProcessId);
            this._processService.UpdateActivityInstance(sub);
            //创建子流程
            this._subHelper.Create(parent, setting.SubProcessTypeName, subProcessId);
        }
Exemplo n.º 20
0
        void IWaitingResumptionHandle.Resume(WaitingResumption waitingResumption)
        {
            var r = waitingResumption as BookmarkResumption;
            var persisted = this._processService.GetWorkflowInstance(r.Process).WorkflowInstance;
            var instance = WorkflowBuilder.CreateInstance(r.Process, this._parser);
            instance.Load(persisted);

            //只能尝试恢复存在的书签
            if (instance.GetBookmarks().Any(o => o.Name == r.BookmarkName))
            {
                instance.Update(r.Process.GetInputs());
                instance.ResumeBookmark(r.BookmarkName, r.Value);
            }
            else
                this._log.WarnFormat("没有在流程“{0}”#{1}中找到名为{2}的书签,取消本次恢复", r.Process.Title, r.Process.ID, r.BookmarkName);
        }