工作流引擎概要分析

一、什么是工作流

工作流,是把业务之间的各个步骤以及规则进行抽象和概括性的描述。使用特定的语言为业务流程建模,让其运行在计算机上,并让计算机进行计算和推动。工作流是复杂版本的状态机。  

上图为工作流退化为基础状态机的例子,小明的状态非常简单,站立->走路->跑步->走路->站立,无限循环,如果让我们实现小明的状态切换,那么我们只需要用一个字段来记录小明当前的状态就好了。 

而对于复杂的状态或者状态维度增加且状态流转的条件极为复杂,可能单纯用字段记录状态的实现方式就会不那么理想。 

如上图所示,现在交给小明的选择就多了起来,当小明获得金钱的时候,他会根据金钱数额的大小来判断接下来该如何行动,如果数额小于等于3000,那么他决定买一个新手机就够了,如果数额小于等于30万,那么小明就决定去学习一下理财,好好利用这笔钱,但如果小明获得的金钱数量超过了30万,他就决定购置一套房屋,但购置房屋的流程是复杂的,小明决定同时完成交首付和贷款的手续。

其实这个流程还不算特别复杂,但到目前为止,单纯用一个字段来表明状态已经无法满足要求了。

工作流解决的痛点在于,解除业务宏观流程和微观逻辑的耦合,让熟悉宏观业务流程的人去制定整套流转逻辑,而让专业的人只需要关心他们应当关心的流程节点,就好比大家要一起修建一座超级体育场,路人甲只需要关心他身边的这一堆砖是怎么堆砌而非整座建筑。 

那么工作流有什么不能解决的问题呢? 

工作流是一个固定好的框架,大家就按照这个框架来执行流程就行了,但某些情况他本身没有流转顺序的要求,比如:小明每天需要做作业,做运动以及玩游戏,它们之间没有关联性无法建立流程,但可以根据每一项完成的状态决定今天的任务是否完结,这种情况我们需要使用CMMN来建模,它就是专门针对这种情况而设计的,但今天我们不讲这个,而是讲讲BPMN协议。

BPMN2.0协议 

对于业务建模,我们需要一种通用的语言来描绘,这样在沟通上和实现上会降低难度,就像中文、英文一样,BPMN2.0便是一种国际通用的建模语言,他能让自然人轻松阅读,更能被计算机所解析。

协议中元素的主要分类为,事件-任务-连线-网关。 

一个流程必须包含一个事件(如:开始事件)和至少一个结束(事件)。其中网关的作用是流程流转逻辑的控制。任务则分很多类型,他们各司其职,所有节点均由连线联系起来。 

下面我就以每种类型的节点简单地概括一下其作用。

网关: 

 

互斥网关(Exclusive Gateway),又称排他网关,他有且仅有一个有效出口,可以理解为if......else if...... else if......else,就和我们平时写代码的一样。 

并行网关(Parallel Gateway),他的所有出口都会被执行,可以理解为开多线程同时执行多个任务。 

包容性网关(Inclusive Gateway),只要满足条件的出口都会执行,可以理解为 if(......) do, if (......) do, if (......) do,所有的条件判断都是同级别的。 

任务: 

 

BPMN2.0协议的所有任务其实是从一个抽象任务派生而来的,抽象任务会有如下行为:

  1. 当流程流转到该任务时,应该做些什么?
  2. 当该任务获得信号(signal)的时候,它是否可以继续向下流转,而任务获得信号的这个动作我们称为Trigger。 

利用如上的抽象行为,我们来解释一些比较常见且具有代表性的任务类型。 

人工任务(User Task),它是使用得做多的一种任务类型,他自带有一些人工任务的变量,例如签收人(Assignee),签收人就代表该任务交由谁处理,我们也可以通过某个特定或一系列特定的签收人来查找待办任务。利用上面的行为解释便是,当到达User Task节点的时候,节点设置Assignee变量或等待设置Assignee变量,当任务被完成的时候,我们使用Trigger来要求流程引擎退出该任务,继续流转。 

服务任务(Service Task),该任务会在到达的时候执行一段自动的逻辑并自动流转。从“到达自动执行一段逻辑”这里我们就可以发现,服务任务的想象空间就可以非常大,我们可以执行一段计算,执行发送邮件,执行RPC调用,而使用最广泛的则为HTTP调用,因为HTTP是使用最广泛的协议之一,它可以解决大部分第三方调用问题,在我们的使用中,HTTP服务任务也被我们单独剥离出来作为一个特殊任务节点。 

接受任务(Receive Task),该任务的名字让人费解,但它又是最简单的一种任务,当该任务到达的时候,它不做任何逻辑,而是被动地等待Trigger,它的适用场景往往是一些不明确的阻塞,比如:一个复杂的计算需要等待很多条件,这些条件是需要人为来判断是否可以执行,而不是直接执行,这个时候,工作人员如果判断可以继续了,那么就Trigger一下使其流转。 

调用活动(Call Activity),调用活动可以理解为函数调用,它会引用另外一个流程使之作为子流程运行,调用活动跟函数调用的功能一样,使流程模块化,增加复用的可能性。 

上面大概介绍了一下常用的节点,下面的图就展示了一个以BPMN2.0为基础的流程模型,尽量覆盖到所介绍的所有节点。 

这里是一个生产汽车的流程,从“汽车设计”节点到“批准生产”节点是一个串行的任务,而审批的结果会遇到一个互斥网关,上面讲过,互斥网关只需要满足其中一个条件就会流转,而这里表达的意义就是审批是否通过。“载入图纸”是一个服务任务,它是自动执行的,之后会卡在“等待原材料”这个节点,因为这个节点是需要人为去判断(比如原材料涨价,原材料不足等因素),所以需要在一种自定义的条件下Trigger,而该图的条件应该为“原材料足够”,原材料足够之后,我们会开始并行生产汽车零件。 

需要注意的是,并行网关在图中是成对出现的,他的作用是开始一系列并行任务和等待并行任务一起完成,拿一个Java中的东西举例子,就是CountDownLatch,fork-join模型也可以类比。  

说到这里,网关的底层逻辑我作为拓展提一句,没听懂也无伤大雅。网关的本质其实是计数器和出口逻辑的混合,它跟其他节点没什么区别,只是他的推动逻辑需要使他的计数器为0,而计数器的总数为网关入口线段的数量,比如“组装”节点前面的并行网关,他的计数器就为4,而前面4个节点,每完成一个就会触发该网关计数器-1。 

当计数器为0的时候,网关会触发选择后续流转的逻辑。 

  • 互斥网关的逻辑为:遍历所有出口连线,满足条件则流出并打断(也就是break掉)。
  • 并行网关的逻辑为:遍历所有出口连线,无条件为所有连线流出。
  • 包容性网关的逻辑为:遍历所有出口连线,满足条件的就流出。
posted @ 2021-11-25 15:34  晨煦风清  阅读(858)  评论(0编辑  收藏  举报