void IWaitingResumptionHandle.Resume(WaitingResumption waitingResumption) { var r = waitingResumption as ProcessStartResumption; var instance = WorkflowBuilder.CreateInstance(r.Process, this._parser); instance.Run(); }
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); }
//HACK:【重要】对单个流程实例的串行顺序调度(不包含仍处于延迟期的调度?),有异常则跳出 /* * 关于父子流程之间的调度顺序影响问题解决 * 在按流程串行调度前提下,按调度影响点分析 * 1.发起子流程:无影响 * 2.子流程结束:子流程本身正常结束即可,对父流程的唤醒排入父流程调度项序列中,按父流程的行为继续调度即可,对应SubProcessCompleteResumption设计 * 3.并行活动中取消子流程节点: * ActivityInstanceCancelResumption节点取消调度被设计为可自动重试, * 直到子流程处于调度项安全状态时才会被删除 */ internal void Resume(IOrderedEnumerable <long> list) { bool error = false; WaitingResumption prev = null, r = null; foreach (var id in list.Distinct()) { r = this._resumptionService.Get(id); //忽略不存在的调度项 if (r == null) { continue; } if (error && !this.AreAtSameFlowNodeIndex(prev, r)) { this._log.WarnFormat("对流程“{0}”#{1}进行串行调度时异常,中断本次对该流程的调度,等待自动或人工重试" , r.Process != null ? r.Process.Title : string.Empty , r.Process != null ? r.Process.ID : Guid.Empty); return; } error = !this.Resume(id); prev = r; } }
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)); }
private bool AreAtSameFlowNodeIndex(WaitingResumption prev, WaitingResumption r) { return(!prev.FlowNodeIndex.HasValue || !r.FlowNodeIndex.HasValue || (prev.FlowNodeIndex.HasValue && r.FlowNodeIndex.HasValue && r.FlowNodeIndex == prev.FlowNodeIndex)); }
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); } }
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); }
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); }
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); } }
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) { 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 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); }
bool ISchedulerService.AnyValidAndUnExecutedResumptions(Process process, WaitingResumption except) { return _resumptionRepository.FindAnyValidAndUnExecutedResumptions(process, except); }
void ISchedulerService.MarkAsError(WaitingResumption r) { r.SetError(true); _resumptionRepository.SetError(r, true); }
void ISchedulerService.Update(WaitingResumption r) { _resumptionRepository.Update(r); }
void ISchedulerService.Add(WaitingResumption r) { _resumptionRepository.Add(r); }