欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Slickflow.NET 开源工作流引擎高级开发(一) -- 流程外部事件的调用和变量存储实现

程序员文章站 2022-03-12 16:57:57
前言:流程实现基本流转功能外,通常也需要调用外部事件,用于和业务系统的交互,同时存储一些流程变量,用于追踪和记录业务数据变化对流程流转的影响。 1. 流程事件 流程执行过程中,伴随各种事件的发生,而且是存在于整个流程的生命周期,即从流程启动一直到流程结束的整个过程都有事件发生。这些事件的发生,业务系 ......

前言:流程实现基本流转功能外,通常也需要调用外部事件,用于和业务系统的交互,同时存储一些流程变量,用于追踪和记录业务数据变化对流程流转的影响。

1. 流程事件

        流程执行过程中,伴随各种事件的发生,而且是存在于整个流程的生命周期,即从流程启动一直到流程结束的整个过程都有事件发生。这些事件的发生,业务系统通常也需要知道一些流程过程的关键节点,或里程碑状态。我们统称为流程事件。

1.1  流程事件触发类型

        流程事件类型的定义是按照事件发生的位置来确定划分,跟流程直接有关的比如有:启动、运行、撤销、退回、返送、跳转、返签和结束等。而跟活动有关的事件类型有:创建、执行和结束等。我们可以用下图来描述常见的事件触发:

 Slickflow.NET 开源工作流引擎高级开发(一) -- 流程外部事件的调用和变量存储实现

1.2  流程事件触发实现

        流程事件的触发,是按照先订阅,后触发的机制来实现。订阅(subscribe)是流程服务接口开放出来的方法,可以直接在这个方法里面注册匿名函数来绑定事件。程序代码如下:

iworkflowservice wfservice = new workflowservice();
var wfresult = wfservice.createrunner(runner.userid, runner.username)
         .useapp(runner.appinstanceid, runner.appname, runner.appinstancecode)
         .useprocess(runner.processguid, runner.version)
         .nextstep(runner.nextactivityperformers)
         .ifcondition(runner.conditions)	//condition on the transiton
         .subscribe(eventfiretypeenum.onactivityexecuting, (activityinstanceid, activitycode, delegateservice) => {
             if (activitycode == "task1")
             {
                 delegateservice.setvariable("name", "book-task1");
                 delegateservice.setvariable("amount", "50");
             }
             return true;
         })
         .run();

  

2. 事件类型节点

        bpmn规范里面,涉及到事件类型的节点,虽然不同于任务类型的节点,但是事件类型的节点通常都是表示一种流程的状态,比如流程的开始和结束是最基本的两个状态。中间事件(intermediate event)是本次我们主要涉及到的事件类型的节点,其它事件类型的节点将在后期的文章中描述到。

2.1 中间事件(intermediate event)

        中间事件(intermediate event)类型的节点一般用于流程中间状态的变换,而且可以作为流程里程碑的事件或状态触发,用于通知业务系统流程的里程碑状态已经发生,或者也可以收到业务系统的反馈的信息,用于一些流程下一步路径的解析。

        比如在中间事件触发时,只有从业务系统中读取到业务变量,然后传入流程的下一步分支选择条件变量中,才能确定下一步的流转路径。这样的处理过程是经常的一种业务场景。一个有中间事件类型节点的流程图示意如下:

 Slickflow.NET 开源工作流引擎高级开发(一) -- 流程外部事件的调用和变量存储实现

2.2 节点上事件的定义

        在流程设计器中,节点上的事件定义主要有两个属性:事件触发的位置(执行前和执行后)、以及事件执行的表达式。一个定义示例描述如下:

        触发位置:执行前

        表达式:slickflow.module.external.ordersubmitservice

2.3 业务服务的代码实现

        上文中提到的表达式是业务服务的程序代码,业务服务的逻辑实现,除了本身的功能代码实现,还需要继承如下的两个接口: externalservicebase 和 iexternalservice。 主要用于明确定义execute()执行方法,然后在引擎内部执行过程中,在调用和执行这个接口方法。具体代码示例如下:

 /// <summary>
    /// 订单提交服务类(对应订单流程中订单提交节点)
    /// </summary>
    public class ordersubmitservice : externalservicebase, iexternalservice
    {
        /// <summary>
        /// 业务逻辑前置调用方法
        /// </summary>
        public override void execute()
        {
            //实现用户自己的业务逻辑
            var id = delegateservice.getid();
            var amount = delegateservice.getvariable("amount");

            dosomethingelse(amount, 20);
        }

        /// <summary>
        /// 业务逻辑具体实现方法
        /// </summary>
        /// <param name="amount"></param>
        /// <param name="newamount"></param>
        private void dosomethingelse(string amount, int newamount)
        {
            var intamount = 0;
            int.tryparse(amount, out intamount);

            if (intamount < newamount)
            {
                delegateservice.setvariable("amount", newamount.tostring());
            }

            //调用其它业务处理逻辑
            var session = delegateservice.getsession();

            //实现其它数据库业务逻辑
            //.............................
        }
    }

   

3. 委托服务的内部机制

        委托服务用于统一处理所有流程发生的时间,跟事件交互过程中,除了触发事件本身以外,还要考虑引擎内部和外部业务系统之间的交互。比如流程变量的保存和读取就是一种交互应用。

3.1 委托服务接口

        委托服务接口定义出事件订阅时候的接口类型,具体代码如下:

 /// <summary>
    /// 委托接口
    /// </summary>
    public interface idelegateservice
    {
        int id { get; set; }
        int getid();
        idbsession getsession();
        string getvariable(string name, nullable<scopetypeenum> scopetype = null);
        void setvariable(string name, string value, nullable<scopetypeenum> scopetype = null);
        string getcondition(string name);
        void setcondition(string name, string value);
        t getinstance<t>(int id) where t : class;
    }

3.2 委托服务继承类

        继承委托服务的接口实现目前有两种类型,一是流程委托服务接口,而是活动委托服务接口。实现的主要目的是对流程变量的读取和存储,还有给外部应用展示流程实例的关键信息。

4. 流程变量

        流程变量是流程流转过程发生的一些数据变化,这些变量一般是来自业务系统的关键参数,而且在流程流转时,通过条件表达式传入,可以决定流程流转下一步的路径选择。

4.1 流程变量类型

        流程变量类型分为全局变量和局部变量。在程序中也可以命名为流程变量(processvariable)和活动变量(activityvariable)。

4.2 流程变量存储

        流程变量的存储是持久化存储在数据库表(wfprocessvariables)中,变量名和数值的key-value是其记录格式。

 delegateservice.setvariable("name", "book-task1");
 delegateservice.setvariable("amount", "50");

  

5. 总结

        流程引擎跟外部事件的交互实现,可以丰富业务过程的状态变化和响应,通过流程变量的存储,记录业务过程中的关键数据变化,同时也做到了对流程分支选择的路径跟踪。程序开发人员可以通过实现外部事件的委托服务,然后再订阅流程过程事件,来彻底实现业务系统跟引擎内部的进一步协作整合。