Flowable 高级用法
事件概览
类型\时机 | 开始(捕获) | 中间 | 边界(捕获) | 结束(抛出) |
---|---|---|---|---|
信号 | 信号中间捕获事件(抛出) | 信号边界事件 | ||
消息 | 消息开始事件 | 消息中间捕获事件 | ||
定时器 | 定时器开始事件 | 定时器中间捕获事件 | 定时器边界事件 | |
错误 | 错误开始事件 | 错误边界事件 | 错误结束事件 | |
取消 | 取消边界事件 | 取消结束事件 | ||
补偿 | 补偿中间抛出事件 | 补偿边界事件 | ||
终止 | 终止结束事件 |
事件
事件用来表明流程的生命周期中发生了什么事。 事件总是画成一个圆圈。 在BPMN 2.0中, 事件有两大分类:捕获(catching) 或 触发(throwing) 事件。
- 捕获(Catching):当流程执行到事件, 它会等待被触发。 捕获事件与触发事件在显示方面是根据内部图表是否被填充来区分的(白色的)。
- 触发(Throwing):当流程执行到事件, 会触发一个事件。触发事件与捕获事件在显示方面是根据内部图表是否被填充来区分的(被填充为黑色)。
事件类型
信号:以广播的方式在流程引擎范围内发送一个信号事件,所有接到信号的节点都需要执行。
就是说, 你可以在一个流程实例中抛出一个信号事件,其他不同流程定义的流程实例 都可以监听到这个事件。然而,有时只希望在同一个流程实例中响应这个信号事件。 比如一个场景是,流程实例中的同步机制,如果两个或更多活动是互斥的。如果想要限制信号事件的范围,可以使用信号事件定义的scope 属性 (不是BPMN2.0的标准属性)
<signal id="alertSignal" name="alert" activiti:scope"processInstance"/>
消息:以点对点的方式发送一个消息事件,只有一个接收者接收到后,节点开始执行
定时器:定时触发节点进行活动
错误:收到一个Flowable定义的业务Error触发节点活动
取消:取消一个事务子流程
补偿:在任务出现异常后,捕获并进行后续的补偿操作。
终止:抛出终止事件,如果有接收错误事件的触发器,则进入,没有则直接终止流程。
信号事件
触发信号事件可通过以下方式
processEngine.getRuntimeService().signalEventReceived("SIGNAL_NAME");
在阻塞住流程执行时,相关信息会录入 ACT_RU_EVENT_SUBSCR 表,等待被唤醒。
开始信号事件
开始信号事件会在接到对应的信号开启一个新的流程。
XML 配置
<definitions>
<signal id="StartEvent" name="START_EVENT"/>
<process id="holidayRequest" name="Holiday Request" isExecutable="true">
<startEvent id="startEvent">
<signalEventDefinition signalRef="StartEvent"/>
</startEvent>
...
</process>
</definitions>
中间捕获信号事件
中间捕获事件会在未接到信号触发之前阻塞,直到接到对应的信号才会继续执行。
XML 配置
<definitions>
<signal id="InterCatchEventSignal" name="INTER_CATCH_EVENT"/>
<process id="holidayRequest" name="Holiday Request" isExecutable="true">
<startEvent id="startEvent"/>
<intermediateCatchEvent id="InterCatchEvent" name="信号捕获中间事件">
<signalEventDefinition signalRef="InterCatchEventSignal"/>
</intermediateCatchEvent>
<sequenceFlow sourceRef="startEvent" targetRef="InterCatchEvent"/>
</process>
</definitions>
用户支付成功后发送信号,等待接收信号后进入发货节点。
中间抛出信号事件
可在 IntermediateThrowEvent 节点抛出 signalRef 引用的信号,对应的捕获事件可收到该信号并执行。
XML 配置
<definitions>
<signal id="InterThrowEventSignal" name="INTER_THROW_EVENT_SIGNAL"></signal>
<process id="holidayRequest" name="Holiday Request" isExecutable="true">
<startEvent id="start"/>
<intermediateThrowEvent id="InterThrowEvent">
<signalEventDefinition signalRef="InterThrowEventSignal"></signalEventDefinition>
</intermediateThrowEvent>
<intermediateCatchEvent id="InterCatchEvent">
<signalEventDefinition signalRef="InterThrowEventSignal"></signalEventDefinition>
</intermediateCatchEvent>
</process>
</definitions>
边界信号事件
信号边界事件的触发条件是接收信号,它具有全局性,可以捕获全局范围的信号。他也可以通过 cancelActivity 设置不中断当前流程。
通过 attach 在某个节点上,如果这个节点是个暂停节点会同时创建一个边界信号事件,接收到对应的信号后,可直接跳过该暂停节点并沿着边界事件的 SequenceFlow 继续执行。(如果是一个报错的异步执行节点,ACT_ID 同样暂停了,但不会创建边界信号事件)
<definitions>
<signal id="BoundaryEventSignal" name="SIGNAL"></signal>
<process id="holidayRequest" name="Holiday Request" isExecutable="true">
...
<boundaryEvent id="boundary" attachedToRef="userTask2" cancelActivity="true">
<signalEventDefinition signalRef="BoundaryEventSignal"></signalEventDefinition>
</boundaryEvent>
<sequenceFlow sourceRef="boundary" targetRef="serviceTask3"/>
</process>
</definitions>
审批节点等待审判时,在接到信号后,流转到更改工单审批节点。
消息事件
触发消息事件可通过以下方式
processEngine.getRuntimeService().messageEventReceived("MESSAGE_NAME", "EXECUTION_ID");
与信号事件不同,信号为广播事件,接收者可有多人;消息事件为独立事件,接收者只能为一人。
消息事件有以下三种:
- 消息启动事件:通过消息启动流程。启动事件如发送一个无订阅关系的消息会抛异常。
- 消息中间事件:通过消息继续执行流程。
- 消息边界事件:通过消息跳过阻塞流程,执行边路逻辑。
定时器事件
定时器在被定义后会被持久化在表中。
使用该事件前需要开启异步执行器:
async-executor-activate: true
定时器事件是根据指定的时间触发的事件。可以用于开始事件,中间事件或边界事件。
- 定时器启动事件:定时器启动事件一般在流程的开始,需要在特定时间、或只需要启动一次、或者需要周期性重复启动时使用。
- 定时器中间捕获事件:定时器中间捕获事件一般用在执行完前置处理后需要过一段时间再开始执行后续处理的场景。
- 定时器边界事件:定时器边界事件一般用在规定时间内任务未处理则走另外的逻辑的场景。
注意:子流程不能有定时器启动事件
定时器定义必须下面介绍的一个元素:
timeDate。使用 ISO 8601 格式指定一个确定的时间,触发事件的时间。示例:
<timerEventDefinition>
<timeDate>2011-03-11T12:13:14</timeDate>
</timerEventDefinition>
timeDuration。指定定时器之前要等待多长时间, timeDuration可以设置为timerEventDefinition的子元素。 使用ISO 8601规定的格式 (由BPMN 2.0规定)。示例(等待10天)。
<timerEventDefinition>
<timeDuration>P10D</timeDuration>
</timerEventDefinition>
timeCycle。指定重复执行的间隔, 可以用来定期启动流程实例,或为超时时间发送多个提醒。 timeCycle元素可以使用两种格式。第一种是 ISO 8601 标准的格式。示例(重复3次,每次间隔10小时):
<timerEventDefinition>
<timeCycle>R3/PT10H</timeCycle>
</timerEventDefinition>
另外,你可以使用 cron 表达式指定timeCycle,下面的例子是从整点开始,每5分钟执行一次:
0 0/5 * * * ?
你可以在定时器事件定义中使用表达式,这样你就可以通过流程变量来影响那个定时器定义。 流程定义必须包含ISO 8601(或cron)格式的字符串,以匹配对应的时间类型。
<boundaryEvent id="escalationTimer" cancelActivity="true" attachedToRef="firstLineSupport">
<timerEventDefinition>
<timeDuration>${duration}</timeDuration>
</timerEventDefinition>
</boundaryEvent>
定时边界事件
在初级工程师无响应一段时间后,会直接通过边界流转到高级工程师。
定时器中间事件
在支付完成后,一分钟后触发发货任务。
错误事件
触发错误事件可通过以下方式:
throw new BpmnError("ERROR_SIGNAL_NAME");
错误启动事件
<definitions>
<error id="StartError" name="START_ERROR"/>
<process id="holidayRequest" name="Holiday Request" isExecutable="true">
<startEvent id="startEvent">
<errorEventDefinition errorRef="StartError"/>
</startEvent>
...
</process>
</definitions>
错误边界事件
错误边界事件依附在某个流程活动中,用于不活流程中抛出的错误,一般用在嵌入子流程或者调用子流程。错误边界事件会接收错误信号,通过设置 errorRef 属性,如果没有使用该属性,错误边界事件将会捕获任何错误事件而不抛出的 errrorCode。
<definitions>
<error id="BoundaryEventError" name="ERROR"></signal>
<process id="holidayRequest" name="Holiday Request" isExecutable="true">
...
<boundaryEvent id="boundary" attachedToRef="userTask2" cancelActivity="true">
<errorEventDefinition errorRef="BoundaryEventError"/>
</boundaryEvent>
<sequenceFlow sourceRef="boundary" targetRef="serviceTask3"/>
</process>
</definitions>
当服务节点抛出错误后,流转到 ERROR TASK 的用户任务。
结束事件
边界错误结束事件
当流程执行到达错误结束事件(error end event)时,结束执行的当前子流程,并抛出错误。这个错误可以由子流程挂载的错误边界中间事件捕获。如果找不到匹配的错误边界事件,将会抛出异常。
中断结束事件
中断结束事件也称为终止结束事件,主要是对流程进行终止的事件,可以在一个复杂的流程中,如果某方想要提前中断这个流程,可以采用这个事件来处理,可以在并行处理任务中。如果你是在流程实例层处理,整个流程都会被中断,如果是在子流程中使用,那么当前作用域内的所有的内部流程都会被终止。
取消结束事件
取消结束事件只能与 BPMN 事务子流程(BPMN transaction subprocess)一起使用。当到达取消结束事件时,会抛出取消事件,且必须由取消边界事件(cancel boundary event)捕获。取消边界事件将取消事务,并触发补偿(compensation)。