触发补偿:
补偿事件可以被指定的活动触发,或者一个拥有补偿事件的作用域触发。补偿的执行是通过一个活动的补偿handler的execution来执行补偿 1.当为某个活动抛出一个补偿时,相关的补偿handler执行的次数与活动完成的次数相同。 2.如果是在当前作用域抛出的补偿,则当前作用域的所有活动都将要被补偿,包括并发分支上的活动。 3.补偿事件会被有层次的触发:如果被补偿的活动时一个子流程,所有包含在这个子流程内的活动都会被触发补偿。如果这个子流程有嵌套的活动,补偿事件会递归的向下抛出。但是补偿事件不会广播到比这个流程高的层级。如果一个补偿在一个子流程内触发,它不会广播到这个子流程的作用域外的活动上去。BPMN规范规定对“同一级别的子流程”上的活动触发补偿。 4.补偿被补偿事件子流程(compensation event subprocess)消费,如果一个被补偿的活动是一个子流程,并且这个子流程包含一个补偿事件子流程,且这个流程被补偿开始事件触发,那么补偿触发的是这个补偿事件子流程而不是触发这个活动包含的子流程。 5.补偿是以相反的顺序执行的,这意味着最后完成的活动,最先获得补偿。 6.中间抛出补偿事件可以用来补偿已经完成的事物子流程
注意:
如果补偿在一个作用域内被抛出,这个作用域包含一个子流程并且这个子流程包含一个带有补偿handler的活动,只有当子流程完成时,并且补偿被抛出,补偿才会传播到子流程的补偿handler。如果嵌套在子流程中的某些活动已完成并有附加补偿处理程序,则如果包含这些活动的子流程尚未完成,则补偿行为不会被执行。 考虑以下示例:
流程变量:
在补偿一个被包含的子流程时,用于执行补偿的handler可以访问子流程完成后,子流程的本地流程变量(local process variables)。为此,子流程作用域内的流程变量将被作为快照保存起来。
由此,我们可以得出一些推论:
1.补偿handler不会去访问当前执行中的子流程中的流程变量 2.快照里不包含与更高层执行相关的流程变量,例如与流程实例执行相关的流程变量:补偿handler可以在补偿被抛出时的状态下去访问这些流程变量 3.变量快照只在被包含的子流程中被采用,其他活动不被支持
当前的一些限制:
1.waitForCompletion="false"在补偿事件中是不被支持的,当用中间抛出补偿事件(intermediate throwing compensation)触发补偿时,在补偿完成后只剩下这个事件(the event is only left after compensation completed successfully) 2.补偿本身是被并发执行的,这个并发执行的顺序与被不补偿活动完成的顺序相反,之后的版本可能会包含一个可选的补偿执行顺序。 3.补偿不会广播到由调用活动产生子流程中去(懵逼脸)
定义一个中间补偿抛出事件:
补偿中间事件被定义为一个中间抛出事件,在这个例子中特定类型的子元素是compensateEventDefinition元素:
<intermediateThrowEvent id="throwCompensation">
<compensateEventDefinition />
</intermediateThrowEvent>
另外,可选参数activityRef可以触发一个特定活动或者作用域的补偿:
<intermediateThrowEvent id="throwCompensation">
<compensateEventDefinition activityRef="bookHotel" />
</intermediateThrowEvent>
二、补偿结束事件(Compensation End Event):
补偿结束事件触发补偿,并且结束当前执行路径。它与补偿中间抛出事件具有相同的行为和限制。
<endEvent id="throwCompensation">
<compensateEventDefinition />
</endEvent>
三、补偿边界事件(Compensation Boundary Event):
依附于一个活动的边界上的中间捕获补偿事件。简称补偿边界事件。用作附着一个补偿handler到一个活动或者一个被包含的子流程上。 补偿边界事件必须直接引用一个相关的补偿handler。 与其他边界事件相比,补偿边界事件有不同的行为策略。其他的边界事件,例如信号边界事件,当活动到达时,信号边界事件就开始了,当活动结束,它也就结束了,并且相关的事件订阅也被取消。补偿边界事件不同,补偿边界事件只有当被依附的活动完全结束后,才会被激活。与此同时,相关的边界事件订阅被创建。当边界事件被触发或者相关的流程实例结束,这个订阅也会被删除。
这就引出了下面的几点:
1.当补偿被触发时,被补偿边界事件依附的活动完成的同时,这个与补偿边界事件关联的补偿handler被调用。 2.如果一个补偿事件依附了一个多实例活动,那么会为每一个补偿事件创建一个订阅。 3.如果补偿边界事件依附于一个活动,且这个活动被包含在一个循环中。则每次这个活动被执行时,都会给它创建一个补偿事件订阅。 4.如果流程实例结束,那么补偿事件订阅也就将被取消掉。
定义一个补偿边界事件:
<boundaryEvent id="compensateBookHotelEvt" attachedToRef="bookHotel" >
<compensateEventDefinition />
</boundaryEvent>
<association associationDirection="One" id="a1" sourceRef="compensateBookHotelEvt" targetRef="undoBookHotel" />
<serviceTask id="undoBookHotel" isForCompensation="true" camunda:class="..." />
因为补偿边界事件是在活动完全结束后才被激活的,所以cancelActivity属性是不被支持的。
四、补偿开始事件(Compensation Start Event):
补偿开始事件只被用作触发一个事件子流程,它不可以被用作发起一个流程实例。这种类型的子流程被称作补偿事件子流程。
部署一个补偿事件子流程的流程定义时,需要注意一下几点:
1.补偿事件子流程只支持被包含的子流程,不是流程级别的。因为这个限制,补偿不会传播到由调用活动产生的子流程实例。 2.在同一层级的子流程只允许有一个补偿事件子流程 3.带有补偿事件子流程的子流程不支持被一个补偿边界事件依赖,因为补偿事件子流程和补偿边界事件有相同的意图,所以他们只能有一个被选用。
补偿事件子流程可以被用作一个被子流程包含的补偿handler。类似补偿边界事件依附一个子流程,补偿事件子流程也只有在补偿事件被抛出时才会被调用。在子流程完成之前,补偿事件子流程将会被调用跟子流程完成的次数相同的次数,在下面这个例子中: