# 工作流模型的基础元素

在数字电路里面,有如下的CMOS基础逻辑门电路,通过这些基础的逻辑门电路可以组合出各种复杂的数字电路模型,来模拟实现各种逻辑运算。

image-20240407192351141

同样的,工作流也是由任务、条件、子过程三种基本元素组合而成(其实子过程也可以当做一种任务),通过他们之间的关系的集合,可以模拟设计各种复杂的业务流程场景。

在Petri网理论中,库所对应的就是条件,变迁对应的是任务。其中,条件有如下几种

  • AND split和AND join
  • OR split和OR join
  • XOR split和XOR join

# 四种基本路由结构

任务结合上述几种条件,可以组合出如下4种基本的路由结构:

  • 顺序路由

  • 分支路由

  • 并行路由

  • 循环路由

# 常见的工作流模式

上述四种基本路由结构更多是从逻辑、理论角度来总结的。由于工作流更多是要应用于业务场景中,所以我们也需要从业务角度来抽象总结一些常见的工作流模式。于是国外有人通过研究总结出一系列带有典型结构特征的工作流模式,例如控制流模式、数据模式、资源模式等。下面我们重点分析控制流模式,控制流模式主要决定哪些任务需要被执行以及以何种顺序执行

  • 分支模式,捕捉流程中的分支场景;

  • 同步模式,描述流程中出现的同步场景;

  • 重复模式,描述可能指定重复的各种方式;

  • 多实例(MI)模式,描述与同一任务相关的流程实例中多个执行线程的情况;

  • 并发模式,反映在流程实例中对并发控制流程施加限制的情况;

  • 触发模式,记录流程上下文中出现的不同触发机制;

  • 取消和完成模式,对可能与流程相关的各种取消和完成场景进行分类;

  • 终止模式,解决流程实例执行何时被认为完成的问题。

    这些模式组识别具有共同焦点的相关模式,我们将在描述每个单独模式时使用这些分组。

控制流模式(Control Flow Pattern)

image-20231130100129393

# 分支模式(branching patterns)

image-20231130131214445

# AND-split

​ AND-Split(也称为并行分支)表示一个分支点,其中多个路径同时开始执行。在这种情况下,所有的分支都会被触发,且各个分支可以并行执行,不需要等待其他分支完成。这种并行执行的方式可以提高效率,因为不同的任务可以同时进行,而不是按照顺序一个接一个地执行。

​ 例如,考虑一个采购流程,其中一个任务是审批采购请求。在审批过程中,可能需要得到多个审批人的同意,而这些审批人可以并行地审批请求。在工作流图中,这个点就可以用 AND-Split 来表示,表示审批流程会分成多个并行的路径,每个路径对应一个审批人的审批任务。

​ AND-Split 通常与后续的合并点(AND-Join)相配合,以确保所有并行分支都完成后再继续执行下一个步骤。这样可以确保流程的同步性,防止因为某个分支较慢而导致整体流程被阻塞。

​ 在实现上,可以显示用图标表示(例如a),也可以像b、c这样隐式方式表示。

image-20240130090728639

如下,是在BPMN中的图形化表示:

image-20240130091829750

# XOR-split

​ XOR-Split 表示在某个点上有多个可能的路径,但只有其中一个路径会被选择执行。XOR 表示“排他性”,即在分支的选择上是互斥的。XOR-Split 可以看作是在流程中做出决策的地方。在这个点上,系统或参与者必须选择其中一个路径,而不是同时选择多个路径。这种分支模式通常用于表示在流程中的一个决策点,根据某些条件或规则选择执行不同的分支。这个有点像条件判断分支的意思。

​ 例如,考虑一个采购流程,其中一个任务是选择供应商。在这个决策点上,可能有多个潜在的供应商,但最终只能选择一个。在工作流图中,这个点可以用 XOR-Split 来表示,表示在选择供应商的时候只能选择一个路径。

image-20240130091612881

​ XOR-Split 通常与后续的合并点(XOR-Join)相配合,以确保只有一个路径被执行后,流程才能继续进行。

在BPMN中,它用下图来表示:

image-20240130091719445

# OR-split

​ OR-Split 表示在某个点上有多个可能的路径,但与 XOR-Split 不同,OR-Split 允许同时选择多个路径执行。这种模式的特点是分支之间是并行的,即所有满足条件的路径都会被执行。OR-Split 可以用于表示在某个阶段有多个独立的任务或条件,而这些任务或条件可以同时进行。当存在多个分支条件,且这些条件之间不互斥,而是可以同时满足时,就可以使用 OR-Split。

​ 例如,考虑一个物流流程,当货物到达仓库后,可能需要进行多个任务,如验收货物、分拣货物、入库等。这些任务可以同时进行,不需要等待其他任务完成。在工作流图中,这个点可以用 OR-Split 来表示,表示在仓库阶段可以并行执行多个任务。

​ OR-Split 通常与后续的合并点(OR-Join)相配合,以确保所有的并行分支都完成后,流程才能继续进行。

image-20240130091953707

BPMN的图形化表示:

image-20240130092038211

# THREAD-split

​ THREAD-Split表示在某个点上有多个可能的路径,但与 AND-Split 不同,THREAD-Split 允许并行执行这些路径,并且各个路径是相互独立的,无需等待其他路径的完成。每个分支在执行时是独立的线程(Thread)。THREAD-Split 主要用于表示在流程中有多个独立的子流程或任务,它们可以同时并行执行,而且彼此之间的执行不影响。这种模式适用于那些可以并行执行的独立子任务,每个子任务都有自己的流程路径,彼此之间没有依赖关系。

​ 例如下图,一个控制线程到达THREAD-Split构造后,结果在传出分支中产生12个并发的控制线程,每个线程触发【填充瓶子】任务的一个独立实例(假设一个纸箱中有12个瓶子)。

image-20240130092339847

​ THREAD-Split 通常与后续的合并点(THREAD-Join)相配合,以确保所有的独立路径都执行完毕后,流程才能继续进行。

尽管这些分支构造中的每一个都对应于现代流程模型中常见的概念,但是它们每个都可以有各种各样的解释和实现方式。

# 同步模式 (synchronization patterns)

同步模式描述了一个或多个分支上的多个控制线程需要合并到一个出去的分支的情况。这种情况在现实生活中的流程中经常出现,其中特定活动的或然执行被暂停,直到流程中的一个或多个先前的活动完成。通常,这些同步事件在工作流上下文中由基于需要同步的传入分支数量的特定结构表示。在实践中出现了四类变体:

  • AND-join,其中所有传入分支都是活动的,并且需要同步指定数量的分支;
  • XOR-join,其中一个传入分支需要同步;
  • OR-join,其中一些传入分支是活动的并且需要同步;然而,需要同步的特定数量直到运行时才知道
  • 线程合并,其中只有一个传入的分支,但是它有多个需要同步的控制流线程。

# AND-join

image-20231130131706045 image-20231130131807413

AND-Join 是用于合并并行执行的分支,确保在所有并行路径上的任务都完成后,流程才能继续进行的一种节点。AND-Join 通常与之前提到的 AND-Split 配合使用,用于同步多个并行执行的路径。

具体来说,AND-Join 用于合并多个并行执行的分支,只有当所有分支上的任务都完成时,流程才能通过 AND-Join 继续执行。这种方式确保了流程的同步性,即使在并行执行的阶段,整体流程仍然保持协调一致。

例如,考虑一个采购流程,其中有两个并行的分支,一个用于审批采购请求,另一个用于支付。在这两个分支上,都需要等待所有审批人完成审批并支付成功后,才能继续执行后续步骤。在工作流图中,这个合并点可以用 AND-Join 来表示。

# XOR-join

image-20231130131835495 image-20231130132149702

XOR-Join 是用于合并具有互斥选择的分支的同步模式。与 AND-Join 不同,XOR-Join 表示在多个分支中只有一个路径会被选择执行。它通常与 XOR-Split 配合使用,表示在某个决策点上只能选择一个分支。

具体来说,XOR-Join 用于合并互斥的分支,即在 XOR-Split 的分支中只能选择一个,而不是同时选择多个。当在 XOR-Split 处做出了选择后,XOR-Join 会将流程引导至下一步。

例如,考虑一个流程,在某个节点有两个互斥的条件,根据某个规则只能选择其中一个条件执行。在工作流图中,这个合并点可以用 XOR-Join 来表示,确保只有一个分支被执行。

XOR-Join 通常用于处理在流程中的决策点,其中只有一个路径能够被选择。它与 XOR-Split 一起使用,形成了互斥的决策结构。

如下是BPMN的图形化描述:

image-20240130093315033

# OR-join

image-20231130131949315 image-20231130132059462

OR-Join 是用于合并具有并行执行的分支的同步模式。与 XOR-Join 和 AND-Join 不同,OR-Join 表示在多个分支中只要有一个完成,流程就可以继续进行。它通常与 OR-Split 配合使用,表示在某个阶段有多个并行执行的任务,只要其中一个完成即可。

具体来说,OR-Join 用于合并并行执行的分支,其中只要有一个分支上的任务完成,流程就可以继续执行。这种模式适用于任务之间相互独立,不需要等待其他任务完成的场景。

例如,考虑一个订单处理流程,其中有多个并行的分支,如支付验证、库存检查、地址验证等。在这种情况下,只要其中一个分支的任务完成,流程就可以继续进行。在工作流图中,这个合并点可以用 OR-Join 来表示。

OR-Join 与 OR-Split 配合使用,形成了并行执行的结构,适用于任务之间不互斥、相互独立的情况。

# THREAD-join

THREAD-join 是一种同步模式,用于合并具有相互独立执行的并行路径。 THREAD-join 与 THREAD-Split 配合使用,表示多个相互独立的子任务或子流程可以并行执行,但需要等待它们全部完成后,才能继续执行流程的下一步。

具体来说,THREAD-join 用于等待所有 THREAD-Split 创建的并行路径上的子任务或子流程全部完成。每个 THREAD-Split 分支都代表一个独立的执行线程(Thread),而 THREAD-join 用于等待这些线程的汇合点。

如下图,在这个例子中,在开始打包纸箱任务之前,线程合并操作将十二个执行线程合并为一个(即,一个纸箱装满了十二个装满的瓶子)。

image-20240130093644147

# 重复模式(repetition patterns)

# 任意循环

  • 定义: 在流程模型中表示具有多个入口或出口点的循环的能力。必须能够将单个入口和出口点与不同的分支关联起来。任意循环模式提供了一种在流程模型中以非结构化的方式支持重复的方法,无需特定的循环操作符或对整个流程模型的格式的限制。
image-20231130202829083

# 结构化循环

能够重复执行任务或子过程的能力。循环有一个预测试或后测试条件与之相关联,该条件在循环的开始或结束时进行评估,以确定是否应继续。循环结构有一个单一的入口和出口点。

这种模式有两种种通用形式 - while循环,相当于编程语言中使用的经典的while...do预测试循环结构;repeat循环,相当于repeat...until后测试循环结构;

while循环允许重复顺序执行指定的任务或子过程零次或多次,只要指定的条件评估为真。预测试条件在循环的第一次迭代之前进行评估,并在每次后续迭代之前重新评估。一旦预测试条件评估为假,控制线程就会传递给循环后面的任务。

repeat循环允许执行任务或子过程一次或多次,直到指定的条件评估为真才继续执行。后测试条件在循环的第一次迭代之后进行评估,并在每次后续迭代之后重新评估。一旦后测试条件评估为真,控制线程就会传递给循环后面的任务。

如下图:(a)中的while循环,(b)中的repeat循环

image-20240130094610409

# 递归

  • 定义: 递归表示在流程中调用自身,形成嵌套的结构。递归可以在每次调用中传递不同的参数,以处理不同的数据或场景。
  • 示例: 考虑一个文件夹结构处理的流程,其中需要递归地遍历文件夹并处理每个文件。在工作流图中,递归可以用于表示在处理一个文件夹时再次调用相同的处理过程以处理其子文件夹。
image-20231130132631348

# 多实例模式(multiple instance patterns)

# 无同步的多实例

在给定的流程实例中,可以创建多个任务实例。这些实例彼此独立并并行运行。完成后无需同步它们。创建的每个多实例任务必须在启动它们的流程实例的上下文中执行(即,它们必须共享相同的流程实例并能够访问相同的数据元素),并且每个任务必须独立于启动它们的任务并且不引用它们。 此模式提供了创建给定任务的多个实例的方法。它适用于在开始生成操作之前就已知所需的单个任务数量,任务可以彼此独立执行,并且不需要后续同步的情况。

例如,交通部收到一份交通违章列表。对于列表上的每一项违章,都会创建一个发出违章通知的任务。这些任务并行运行直到完成,并且不触发任何后续任务。它们无需在完成时同步。

image-20231130203608097

下图是BPMN的图形化表示:

image-20240130095505455

其中,isSequential用来控制任务实例时顺序执行还是并发执行:

  • 顺序执行(同步):这些创建的多个任务实例时依次执行,而不是一起并发执行。
  • 并发执行(异步):这些创建的多个任务实例是并发同时执行。

这个跟编程语言里面的For循环功能类似。

# 具有先验设计时知识的多个实例

在给定的流程实例中,可以创建多个任务实例。在设计时已知所需实例的数量,这些实例彼此独立并行运行。在触发任何后续任务之前,需要在完成时同步任务实例。

此模式为指定任务的并发执行提供了基础,预定义执行次数。它还确保在启动后续任务之前,所有任务实例都已完成。此模式提供的一个优势是,无需在流程模型中显式标识并行运行的任务的每个实例。相反,该模式可用于表示将执行多个并发实例的指定任务,当所有实例完成时,控制线程将传递给后续任务。

image-20231130203956757

# 具有先验运行时知识的多个实例

在给定的流程实例中,可以创建多个任务实例。所需实例的数量可能取决于多个运行时因素,包括状态数据、资源可用性和进程间通信,但在创建任务实例之前已知。一旦启动,这些实例彼此独立并行运行。在触发任何后续任务之前,需要在完成时同步实例。

具有预先运行时知识的多实例模式提供了以同步方式执行给定任务的多个实例的方法,确定将创建多少实例的决定被推迟到启动任务之前的最后时刻。

image-20231130204829532

前面两个的区别是,前者是在定义流程时就知道任务实例数量,后者是要遭运行时才知道任务实例数量。

# 触发器模式(trigger patterns)

过程执行通常不会与其所在的更广泛的操作环境孤立地进行。有各种情况下,流程中特定任务的执行需要与环境外的事件同步或由其触发。因此,两种类型的触发模式提供了实现这一目标的方法。瞬态触发器提供了一种基于环境信号启动任务的方法。信号是短暂的,如果它没有立即引发任务的启动,它就会丢失。在其他情况下,信号已经发生的事实仍然很重要。这被持久触发器所认可,它允许将已发送到任务的触发器保留,直到任务接收到控制线程。下面将讨论这两种模式。

image-20231010235735715

在工作流模式中,触发器模式可以根据触发事件的持续时间分为瞬态触发和持续触发两种类型。这两种触发器模式用于定义工作流何时响应外部事件或条件。

# 瞬态触发

瞬态触发器 描述:任务实例能够通过来自流程的其他部分或外部环境的信号来触发。这些触发器具有瞬态性质,如果接收任务没有立即采取行动,它们将丢失。只有在接收到触发器时有任务实例等待它时,触发器才能被利用。

瞬态触发器是一种常见的表示预定义事件已发生并且应该进行适当处理响应的信号方式,包括启动单个任务、一系列任务或流程中的新执行线程。瞬态触发器是必须在收到后立即处理的事件。换句话说,它们必须立即启动任务。流程对瞬态触发器没有任何形式的记忆。如果没有立即采取行动,它们将无可挽回地丢失。

如下图,任务A在收到所需的输入触发器之前无法进行。如果触发器发送给A,但控制线程未响应,则触发器将被丢弃。

image-20240130130305896

由于接收信号的任务可以在流程中的起始或者中间位置,如果在起始位置,则相当于触发创建一个流程实例运行。如果在中间位置,则相当于流程实例的任务在等待信号响应。

# 持续触发

任务实例能够通过来自流程的其他部分或外部环境的信号来触发。这些触发器具有持久性形式,并由流程实例保留,只要它继续执行,就预期它们可以在未来某个时候被接收任务采取行动。

持久触发器本质上具有持久性,确保它们在传输过程中不会丢失,并在目标任务可以处理它们之前进行缓冲。

如下图,说明了持久触发器的操作。在这种情况下,所有触发器都被保留并在控制线程到达任务A时逐个消耗。

image-20240130130728071

# 取消和完成模式(cancelation & completion patterns)

在执行业务流程时,一个常见的需求是能够选择性地取消流程实例中的部分或全部任务。通常情况下,取消操作与流程实例达到预定状态(例如执行某个任务)相关联,尽管在某些情况下(如取消整个案例),触发事件可能来自于流程实例之外。根据取消操作的范围和被取消任务的类型,取消这个概念可以分为多个层次。因此,我们可以将其划分为五个不同的模式。

这五个取消和完成模式是:

  • 取消单个任务,当流程实例达到指定状态时,撤销特定任务实例;
  • 取消多实例任务,当流程实例达到指定状态时,撤销多任务实例的所有实例;
  • 完成多实例任务,当流程实例达到指定状态时,撤销多任务实例的其余实例(在相关的情况下,触发流程中的后续任务);
  • 取消区域,当流程实例达到指定状态时,撤销流程中指定部分的所有任务实例;
  • 取消案例,撤销流程中的所有任务实例。 下面将更详细地讨论这些模式。

# 取消单个任务

在任务执行前或执行过程中,启用的任务可能会被撤销。如果任务已经开始,它将被禁用,同时在可能的情况下,当前正在运行的实例将被停止并移除。取消任务模式提供了撤销已启用或正在执行的任务的功能,确保任务不会开始或完成执行。

如下图所示,当任务A完成后,正在执行的任务B(在同一流程实例中)的所有实例都将被取消。取消任务B涉及移除所有正在执行的实例以及可能存在于用户任务列表中的任何对其的引用。由于任务B的取消,其后续的任何任务都不会被启动。

需要注意的是,取消操作并不能保证任务的终止,任务可能会继续执行到完成。实际上,取消操作与继续执行的决策类似于延迟选择,其中取消事件与处理取消的资源分配任务之间存在竞争关系。一般来说,任务的取消并不能得到保证。然而,在实际应用中,一旦发起取消操作,任务被取消的可能性通常大于用户完成任务的可能性。

image-20240910230942189

如下是在BPMN中的图形化表示:

image-20240130131733288

# 取消多实例任务

在给定的流程实例中,可以创建一个任务的多个实例。这些实例彼此独立并同时运行。在任何时候,都可以取消多实例任务,尚未完成的实例将被撤回。已经完成的任务实例不受影响。任务取消后,后续任务不会被启动。这种模式提供了在执行过程中随时取消多实例任务的方法,以便取消任何剩余的实例。不允许启动新的实例;然而,已经完成的实例不受取消影响。

如下图所示,当任务A启动时,将取消当前正在执行的任务B的所有实例(在同一流程实例中)。取消任务B包括移除所有执行实例,以及可能存在于用户任务列表上的对它们的任何引用。由于任务B的取消,后续任务(即任务C)不会被启动。被取消的任务B的各个实例(即B1、B2、B3)被认为没有成功完成(例如,在日志中记录为不成功)。

image-20240130190720299

如下是在BPMN的图形化表示:

image-20240130190842052

BPMN通过一个多实例活动,其边界上附加了信号事件,来支持这种模式。当需要取消多实例活动时,触发信号事件以终止任何剩余的实例。

# 完成多实例任务

在给定的流程实例中,可以创建一个任务的多个实例。这些实例彼此独立并同时运行。在触发任何后续任务之前,需要在完成时同步这些实例。在执行过程中,可能需要强制完成任务,以便撤回任何剩余的实例并将控制线程传递给后续任务。这种模式提供了在执行过程中随时完成尚未完成的多实例任务的方法,以便撤回任何剩余的实例并立即将控制线程传递给后续任务。不允许启动新的实例。已经完成的实例不受取消影响。

如下图所示,当任务A完成时,将取消正在执行的任务B的所有实例(在同一流程实例中)。任务B的完成涉及移除所有已启用和正在执行的实例。已经完成执行的任何实例(在这个例子中,任务实例B2)不受影响。一旦触发完成操作,后续任务(即任务C)将启动。在完成操作之前已经完成执行的强制完成任务的任何实例都被认为已经成功执行(例如,任务实例B2),任何被取消的实例(例如B1、B3)都不被认为已经成功完成。这些考虑因素也反映在执行日志中的相关条目中。

image-20240130191152408

# 取消区域

在流程实例中,具有禁用一组任务的能力。如果任务已经在执行(或当前已启用),那么它们将被撤回。任务不必是整个流程模型的连接子集。能够取消一系列(可能无关)任务的选项是一种有用的能力,特别是在处理意外错误时。

例如,当任务A启动时,任务B、C和G的所有已启用或正在运行的实例(在同一流程实例中)都将被取消。一旦取消操作生效,由于取消操作,不会启动那些被取消的任务之后的任何任务。

image-20240130191506638

# 取消流程实例

删除整个流程实例,包括当前正在执行的任务、未来可能执行的任务以及所有子流程。该流程实例将被标记为未成功完成。此模式提供了一种方法,用于终止指定的流程实例并撤销与其相关的所有任务实例。

BPMN通过终止结束事件来支持这一操作,允许终止流程实例中所有正在执行的活动。

# 终止模式(termination patterns)

流程实例可以通过两种不同的方式终止。一种可能性是,当流程实例现在或在任何未来时间都没有更多的工作要做时,它可以被认为已经完成。另一种选择是,当流程达到特定状态时,它可以被认为已经完成。这两种情况为两种终止模式提供了基础:隐式终止和显式终止,随后将进行讨论。

# 显式终止

当一个流程(或子流程)实例达到预设的状态时,应当终止该流程。这通常通过一个或多个特定的结束节点来表示。一旦到达这些结束节点中的任何一个,将取消流程实例中的所有剩余任务,并将整个流程实例标记为已成功完成,无论是否还有正在进行或待执行的任务。这种模式的目的是明确定义何时可以将流程实例标记为完成。这通常在控制线程到达流程模型中的预设状态时发生,通常由模型结束处的一个或多个特定终止节点来表示。在流程中有一个单一的结束节点会使其在其他组合中的包含更为简洁。

如下图,有两个结束节点。一旦控制线程到达这些结束节点之一,流程实例就被视为完成,并且与其相关的所有其他工作项都被撤回。

image-20240131090753982

# 隐式终止

当一个流程(或子流程)实例在现在或未来没有剩余的工作项需要完成,并且流程实例没有陷入死锁的情况下,应该将其终止。这种情况下,我们有一个明确的标准来确定流程实例是否已成功完成。这种模式的目的是提供一种最实际的方式来确定何时可以将流程实例标记为完成。也就是说,当流程中没有剩余的工作需要完成,并且不可能在未来出现新的工作项时,我们可以认为该流程已经完成。

如下图,有三种可能的结束场景:(1)在任务F后完成,(2)在任务K后完成,(3)在任务F和K后完成。隐式终止提供了一种有效的方式来确定流程何时完成,因为没有单一的结束任务,有几种可能的结束场景。

image-20240131091105920

终止模式的选择取决于流程的设计目标和业务需求。以下是一些考虑因素:

  • 明确性和可读性: 显式终止通常使流程更加明确和可读,因为流程的结束条件和节点是直观可见的。
  • 自动化和灵活性: 隐式终止提供了更大的自动化和灵活性,系统可以根据动态的条件判断流程何时结束。
  • 异常处理: 如果流程中可能发生异常情况需要进行处理,显示终止通常更容易实现异常处理逻辑。

终止模式的选择应该根据具体的业务场景和流程设计的要求进行。有时候,工作流中可能会同时使用显式终止和隐式终止的方式,以满足不同的流程节点和需求。

最后更新: 9/12/2024, 11:20:51 PM