通过使用 WebSphere Process Server V6.0 中的 Business Process Choreographer 这个新功能,可以提高进程的动态性,并实现涉及多个实例的工作流模式。
引言:WebSphere Process Server V6.0 和事件处理程序
IBM WebSphere® Process Server V6.0 包括一个 Web 服务业务流程执行语言(Web Services Business Process Execution Language,WS-BPEL)流程引擎,称为 Business Process Choreographer。该引擎是 WebSphere Business Integration Server Foundation V5.1 中的流程引擎的后续版本。V6 中提供了许多功能,其中 Business Process Choreographer 支持在业务流程中定义和执行事件处理程序。本文说明了事件处理程序的概念,并提供了一些示例来说明可以如何使用事件处理程序来提高 WS-BPEL 流程的动态性。有关代码示例,请参阅参考资料。


|
回页首 |
|
什么是事件处理程序?
事件处理程序之所以得到了广泛应用,主要得益于图形用户界面(Graphical User Interface,GUI)的出现。通常,GUI 程序的结构经过特殊设计,因此程序可以对外部事件(如单击鼠标按钮和拖动滚动栏)做出响应。这些程序中的自定义代码包含事件处理方法,如 onKeypressed()、onClick();而基础结构提供事件调度功能,以检测外部事件和调用对应的自定义事件处理方法。
事件处理程序与软件系统的其他部分的不同之处在于,它们处理的是与程序的执行独立且异步的事件。
可能会在以下情况发生此类事件:
- 程序生命周期内的任何时间
- 任意次数(即 0、1、2……n 次)
在 WebSphere Business Integration Server Foundation V5.1 中,Business Process Choreographer 支持将各种活动作为流程内的构造来接收和选择,以响应外部事件。不过,这些活动并不能处理满足上述条件的事件。如果流程要按照正常方式执行,则接收或选择活动必须执行一次,且仅执行一次。因此,在对流程进行建模时,您必须知道预期会出现多少传入事件,以及在流程执行期间事件的预期发生时间(如果希望使用接收或选择活动)。
WS-BPEL 指定了另一个构造来处理外部事件:事件处理程序。与接收或选择活动类似,此类事件处理程序可以对外部事件进行响应,从而提高其动态性。
业务流程上下文中的外部事件将自身声明为以下类型之一:
- 对流程提供的操作的调用:例如,声明处理流程支持在流程当前正在运行时取消声明。这种情况可以出现一次,也可以根本不发生。为此,流程的客户机将调用使用事件处理程序实现的取消操作。
- 超时过期:例如,管理人员希望在流程执行时间超过一周时得到通知。
- 重复的超时过期:例如,管理人员希望在流程执行时间超过一周时得到通知。在一周结束后,管理人员希望在该进程结束前每天都得到通知。


|
回页首 |
|
如何在 WS-BPEL 中指定事件处理程序?
WS-BPEL 定义事件处理程序可以与整个流程关联,也可以与流程中的每个范围关联。范围是 WS-BPEL 中的一个特殊活动,可为其所包含的活动提供行为上下文。范围可以提供错误处理程序、事件处理程序、补偿处理程序、局部变量、本地伙伴连接和本地相关集。
事件处理程序的定义包括两个部分:
- 第 1 部分定义要调用的事件处理程序的条件;即,它定义事件处理程序的类型。
- 第 2 部分定义事件处理程序必须进行的操作;在此部分中,将定义事件处理程序的实现及其业务逻辑。
我们接下来将讨论事件处理程序的各个部分:
第 1 部分:要调用的事件处理程序的条件
WS-BPEL 定义了两种类型的事件处理程序,如下所述:
onEvent 事件处理程序,处理出现的外部消息事件。这是对操作的调用。
onAlarm 事件处理程序,处理超时过期的情况。
另外,WS-BPEL 还定义了 onAlarm 事件处理程序的以下两个子类型:
- onAlarm
<for> | <until> 处理单个超时事件。
- onAlarm
(<for> | <until>)? <repeatsEvery> 处理重复的超时事件。
第 2 部分:事件处理程序必须进行何种操作?
在事件处理程序内,您可以指定任何标准 BPEL 活动。流或序列之类的组合活动在指定事件处理程序内所进行的操作时尤为有用。我们将在下面了解到,为了获得事件处理程序实例的已确定范围的局部变量,可以将活动的范围定义为事件处理程序的直接子项。


|
回页首 |
|
事件处理程序的运行时语义
对于每个事件处理程序,当与其关联的流程或范围启动时,将启用它;当与其关联的流程或范围结束时,将禁用它;只要启用了它,就可以启动其多个实例。
启用
事件处理程序是在与其关联的范围启动时启用的。与整个流程关联的事件处理程序将在创建接收或选择活动接收到其传入消息时立即启用。(请注意,WS-BPEL 将在发送到 createInstance 属性设置为 yes 的接收或选择活动的消息送达时隐式地创建流程。在本文中,此类活动称为“创建接收或选择活动”。)这样做的根本原因是,事件处理程序必须能够访问保存传入消息的变量。
禁用
与范围关联的所有事件处理程序将在范围的正常处理完成后禁用。如果在范围结束时事件处理程序的实例仍然在运行,则将允许其继续完成。范围的整体完成将延迟到所有正在运行的事件处理程序都完成时为止。
务必对启用 和调度 加以区分。关联的范围启动时,相应的事件处理程序就已启用 了。
在以下条件下,onEvent 事件处理程序实例为已调度:
- 事件处理程序已启用,且
- 已在流程上调用了关联的操作
在以下条件下,将调度 onAlarm 事件处理程序:
- 事件处理程序已启用,且
- 已到达指定的超时
与错误处理的关系
事件处理程序被视为范围的正常处理的一部分。事件处理程序内的错误将采用与关联范围内的错误一样的方式处理。如果在范围内(或在与范围关联的事件处理程序中)出现错误,错误处理程序将禁用所有与该范围关联的事件处理程序,然后隐式地终止当前处于活动状态的范围内直接包含的所有活动。这包括当前处于活动状态的事件处理程序内的活动。
并发性
多个 onEvent 和 onAlarm 事件可以并发出现,它们将作为并发活动对待。事件处理程序允许具有多个同时处于活动状态的实例。将为事件处理程序的每个实例提供该事件处理程序内定义的所有进程数据和控制行为的私有副本。


|
回页首 |
|
需要考虑的问题
WS-BPEL 定义了若干应用到事件处理程序的限制。在定义事件处理程序时,必须仔细考虑这些限制。此外,事件处理程序带来的高并发性可能会导致新问题。
接收冲突
WS-BPEL 要求具有相同的端口类型、操作、相关集和伙伴链接的多个接收或选择活动不能同时激活,否则将引发 bpws:conflictingReceive 标准错误。这也适用于事件处理程序。即,在此限制之下,事件处理程序限定为接收活动。此限制的根本原因在于,如果流程中有多个接收活动等待相同的端口类型、操作、相关集和伙伴链接,则流程引擎不知道应将传入消息交付给哪个接收活动。
Business Process Choreographer 进一步加强了此限制,因为无法基于相关集和伙伴链接区分传入消息。因此,Business Process Choreographer 有如下强制要求:在一个流程实例内,最多一个具有相同端口类型和操作的接收或选择活动或者事件处理程序处于活动状态。
此限制的示例包括以下情况:
- 如果具有特定端口类型和操作的接收或选择活动已激活,而同时另一个具有相同端口类型和操作的选择或接收活动已经在等待,则将引发
bpws:conflictingReceive 标准错误。
- 如果启用了具有特定端口类型和操作的事件处理程序,然后激活了具有相同端口类型和操作的接收或选择活动,则将引发
bpws:conflictingReceive 标准错误。
- 如果具有特定端口类型和操作的接收或选择活动正在等待,然后启用了一个具有相同端口类型和操作的事件处理程序,则将引发
bpws:conflictingReceive 标准错误。
请求冲突
WS-BPEL 对请求-响应操作施加了其他限制。由于 WS-BPEL 中的相关集始终仅标识一个流程实例,因此客户机无法使用 WS-BPEL 方法来区分属于相同端口类型、操作、相关集和伙伴链接的不同应答。因此,WS-BPEL 要求,在任何给定时间,对于每个端口类型、操作、相关集和伙伴链接,每个流程实例只能有一个请求-响应操作。否则,必须引发 bpws:conflictingRequest 标准错误异常。此限制与接收冲突限制不同,因为请求-响应操作在对应的应答活动执行完成之前都处于活动状态。
与上面 bpws:conflictingReceive 错误的情况类似,Business Process Choreographer 仅允许每个进程实例、端口类型和操作同时具有一个处于活动状态的请求-响应操作。此规定的结果是,如果某个事件处理程序实现了一个请求-响应操作,则在任何时间点,只能有一个此类事件处理程序的实例处于活动状态。
对变量的并发访问
从事件处理程序内访问变量受到 WS-BPEL 范围规则控制。让我们通过一个示例来说明此情况,如图 1 中所示。
图 1. WS-BPEL 流程中的变量可见性
假定我们有一个名为 AProcess 的流程。该流程包含范围 MainScope,该范围具有一个关联的事件处理程序。该事件处理程序包含一个嵌套范围 NestedScope。定义了以下变量:
- 在流程级别,定义了变量
VP
- 在
MainScope 内,定义了变量 VM
- 事件处理程序中包含一个隐式创建的变量,称为
VEH
- 在
NestedScope 内,定义了变量 VNS
WS-BPEL 定义了以下访问和可见性规则:
- 流程级别变量
VP 对整个流程的所有活动可见(即可以访问该变量)
- 在
MainScope 内定义的变量 VM 对 MainScope 内的所有活动和与 MainScope 关联的事件处理程序及事件处理程序内的嵌套范围内的所有活动可见
- 在事件程序中隐式定义的变量
VEH 对事件处理程序和事件处理程序内嵌套的范围内的所有活动可见。请注意,此变量无法从 MainScope 内的活动进行访问
NestedScope 中定义的变量 VNS 只对 NestedScope 内的活动可见
在运行时,每个流程实例只能具有变量 VP 和 VM 的一个实例。对于已启动的每个事件处理程序实例,只能具有一个 VEH 和 VNS 变量的实例。
事件处理程序可能有多个实例处于活动状态,而变量 VP 和 VM 只能具有一个实例。如果事件处理程序内的某个活动要访问变量 VP 和 VM,则它必须与同时处于活动状态的所有其他事件处理程序实例共享此变量。
由于 Business Process Choreographer 在事务中执行活动,因此对共享变量的并发访问由事务隔离和并发性控制进行控制。
建模不恰当的事件处理程序可能导致死锁和由于锁导致长时间等待。对于 Business Process Choreographer,可以通过在特定活动上设置 transactionalBehavior 属性类来控制事务的范围。您可以指定某个活动是否参与某个事务,要求在活动执行前或执行后进行提交,或要求使用其自身事务进行操作。
为了减少锁等待的影响,可以在修改其自身事务内的全局变量的事件处理程序中执行活动。
范围隔离
范围可以定义为彼此隔离。根据 WS-BPEL 的要求,范围隔离可在控制对共享变量的访问时提供并发访问控制。范围隔离扩展了访问分布在多个事务上的情况下的共享变量访问控制。
这样做的结果是,如果事件处理程序包含范围隔离,且启动了此事件处理程序的多个实例,则将严格约束这些实例的并发执行。由于这可能与事件处理程序的整体思想相背离,因此应在事件处理程序内谨慎地使用范围隔离。
请注意,只有您的范围在一个事务中读取全局变量,并在另一个事务中更新同一全局变量时,才需要使用范围隔离。在大多数情况下,可以避免这样的变量访问模式。


|
回页首 |
|
事件处理程序使用情况
一种简单的使用事件处理程序的情况就是对外部事件进行响应。WS-BPEL 概略描述了三个此类示例,如下所示:
- 第一个示例是汽车订购流程,其中的显式订单取消操作是由一个
onEvent 事件处理程序实现的。
- 第二个示例是汽车订购流程中的
onAlarm 事件处理程序。在此示例中,如果订单流程的处理时间超过了特定的时间值,将触发一个事件处理程序,然后可以执行特定的操作。此操作并未在示例中明确给出。
- 第三个示例处理旅行预订流程,该流程管理客户的旅行预订情况。预订更新是通过事件处理程序进行管理的;这是一个
onEvent 事件处理程序,用于接收和处理来自旅行预订系统的更新消息。
可以从 Business Process Choreographer 示例站点上找到另一个例子。此示例处理的是招聘流程。每个流程与一个处于活动状态的招聘对应。招聘在指定时间内处于活动状态。在招聘处于活动状态时,流程可以接收申请。申请消息送达后,系统会将该申请添加到列表中,并发回一条应答消息。招聘过期时,系统会将申请发送给经理,然后流程就结束了。招聘的过期是通过 onAlarm 事件处理程序实现的,而单个申请的处理则是通过 onEvent 事件处理程序实现的。有关详细信息,请参阅 BPC 示例网站上的 BPEL event handling document。
W. van der Aalst 等人维护的 Workflow Patterns Web site 对各种工作流模式进行了归类。有关可通过事件处理程序实现的模式示例,请参阅该页上的“Advanced Branching and Synchronization Patterns”部分和“Patterns Involving Multiple Instances”部分。
实现这些模式的基本方法是进行以下工作:
- 定义一个执行事件处理程序内业务逻辑的的特定部分的流程
- 在流程内多次调用此事件处理程序,从而以这种方式创建业务逻辑的这一部分的并行实例(其数量不定)
一个简单的例子
让我们举例说明此方法。在我们的示例中有一个审阅流程,其中,文档的作者通过指定所有应当对文档进行审阅的人员来开始审阅流程。此场景存在几个问题:首先,审阅是人工活动,要花费大量的时间。另外,审阅人员并不依赖其他审阅人员的审阅结果。因此,以并行方式进行审阅将带来很多好处。另外,在建模时,我们并不知道该流程所需的审阅人员数量。
建模人员就面对这个一个问题:他无法使用任何本机 WS-BPEL 活动来建模此场景。他可以使用流活动来建模并行性,但流具有必须在建模时确定分支数量的缺点。或者,他可以使用循环活动来建模未知数量的分支,但循环体是以串行方式执行的。
事件处理程序可以帮助处理这种情况。粗略的想法是,我们建模一个触发审阅活动的事件处理程序。在循环中,将为每个审阅人员启动此事件的一个实例。这就恰当地处理了与此场景关联的那两个主要问题:可以并行进行审阅工作,而且不需要在建模时知道将参与审阅的审阅人员数量。
图 2 显示了构成上面描述的审阅流程的 WS-BPEL 活动。为了完全理解此处所讨论的内容,请从 BPC AdvancedEventHandlers project page 获得此项目的工作区,并将其导入到 WebSphere Integration Developer 中。然后,您可以在了解所有的细节,包括 Java 代码片段中的 Java™ 代码、各种变量的数据类型以及事件处理程序中的成员表达式。下面的讨论对该流程的业务逻辑进行了概略介绍和说明。
图 2. ReviewProcess 的主要部分
- 初始审阅活动创建流程。将文档和审阅人员列表输入流程,并存储在流程的输入变量中。
- 范围
MainScope 中包含为各个审阅人员启动各种事件处理程序实例的逻辑。红色小旗表明 Scope1 与一个事件处理程序关联。
InitializeVariables Java 代码片段准备各个变量。将准备以下变量:
numOfReviewers——我们将此变量设置为审阅人员的数量。流程在循环条件中将其作为上边界使用。
activeReviews——我们将此变量设置为审阅人员的数量。如果审阅完成,事件处理程序会对此变量进行递减。该变量达到零后,事件处理程序的该实例将调用 ReceiveReviewFinishedNotification 操作来通知 MainScope 所有审阅已完成。
reviewStartRequest——此为 StartSingleReview 调用活动的输入变量。此调用活动将调用事件处理程序。该变量中包含一个索引,以告知事件处理程序应使用流程的输入变量中审阅人员列表内的哪个审阅人员。
- result——此变量以列表的形式存储所有审阅结果。为了进行此操作,需要使用空对象初始化此列表。
- 流程将会为每个审阅人员迭代一次 WhileLoop。它将一直循环到事件处理程序的输入消息的索引达到审阅人员的数量为止。
- 调用活动将为单个审阅人员调用事件处理程序实例。
- 活动
incrementIndex 会将索引值增加一。
ReceiveReviewFinishedNotification 接收活动将一直等待,直到最后一个运行的事件处理程序实例发送通知来指示所有事件处理程序已完成为止。然后继续在 MainScope 中导航。
尽管根据 WS-BPEL,MainScope 不能在所有运行的事件处理程序实例完成前完成,流程仍然需要此活动,因为事件处理程序操作是 request-only 类型的操作。此类操作采用异步方式调用,并不能保证这些调用的顺序。没有这个接收活动,MainScope 可能会在事件处理程序启动前完成。为了保证流程执行所有事件处理程序,此接收活动将等待最后一个事件处理程序实例发送完成通知。
- 对审阅结果进行评估。
- 返回一个结果消息。
图 3. ReviewProcess 中的事件处理程序
图 3 显示了构成事件处理程序的构造。以下是各个构造及其包含的内容:
onEvent 构造表示事件处理程序。在此构造中,隐式定义了一个名为 myReviewStartRequest 的变量;该变量是事件处理程序实例的局部变量。
- 事件处理程序包含一个范围。定义局部变量要求使用此范围,以便每个事件处理程序实例都使用其自身的数据。如果没有局部变量,所有事件处理程序实例都将在相同的全局变量实例上工作。只有事件处理程序完成了其业务逻辑后,它才会更新全局变量 result,以将结果返回到
MainScope。
SetupLocalVariables Java 代码片段准备事件处理程序内所需的局部变量。最重要的是,它将设置 myDocumentForReview 变量,以提供 review_paper 手动任务的输入。
review_paper 意味着由相关人员执行实际的审阅。通过执行成员赋值表达式 %htm:input.\input/reviewer% 来确定任务的所有者。此表达式使用任务活动的输入消息。此表达式的一般结构为 %htm:input.[part]\<xpath-query>%。有关此表达式的参考信息,请参阅 WebSphere Integration Developer V6.1 的 Replacement expressions in descriptions and staff assignments。在我们的示例中,我们使用的是仅包含一个部分的消息,因此可以忽略“[part]”,故而该表达式缩减为 %htm:input.\<xpath-query>%。Xpath 查询将首先导航到消息的 input 元素,将在其中找到 DocumentForReview 类型的数据对象,然后提取 reviewer 属性。
SetResultAndDecrementCounter 将审阅结果从局部变量 myReviewResult 复制到全局变量 results 中。此全局变量中保存了一个 ResultOfSingleReview 对象列表。另外,还会递减 activeReviews 计数器值。由于此活动将修改全局变量,因此其 transactional behavior 属性设置为值 RequiresOwn。即,此活动在单独的事务中执行。
Choice 活动仅具有一个 case 语句——AllInstancesFinished。此条件检查 activeReviews 变量是否已经为零。如果是,当前事件处理程序实例则为最后一个事件处理程序实例,事件处理程序将调用 MainScope 中正在等待的 ReceiveReviewFinishedNotification 活动。
sendReviewFinishedNotification 调用 MainScope 中正在等待的 ReceiveReviewFinishedNotification 接收活动。
图 4. ReviewProcess 的全局变量
reviewCycleInput 接收外部请求的输入。
result 包含所有审阅人员的注释的数组。
reviewStartRequest 事件处理程序的输入变量。
activeReviews 对正在运行的事件处理程序进行计数。
numOfReviewers while 循环的上边界。
reviewSuccces 如果所有审阅人员都接受了文档,则设置为 true。
reviewFinishedNotification ReceiveReviewFinishedNotification 的输入。
事件处理程序内的局部变量是从事件处理程序的输入变量 myReviewStartRequest 组合而成的,如图 5 中所示,这些变量在事件处理程序的范围内定义为局部变量,如图 6 中所示。
图 5. OnEvent 定义
onEvent 定义指定了事件处理程序的输入变量 myReviewStartRequest,如图 5 所示。这将创建一个事件处理程序实例的局部变量。在图 6 中,myDocumentForReview 指向要审阅的文档的本地副本,而 myReviewResult 指向该审阅的本地结果。
图 6. OnEvent 定义
清单 1 和清单 2 显示了在事件处理程序内运行的 Java 代码片段 SetupLocalVariables 和 SetResultAndDecrementCounter。
清单 1. Java 代码片段 SetupLocalVariables 的代码
BOCopy copyService =
(BOCopy)ServiceManager.INSTANCE.locateService( "com/ibm/websphere/bo/BOCopy");
BOFactory factory =
(BOFactory)ServiceManager.INSTANCE.locateService("com/ibm/websphere/bo/BOFactory");
// setup local variable myDocumentForReview so that it can be used as input for review_paper
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
Type type = getVariableType("myDocumentForReview");
myDocumentForReview = factory.createByType(type);
// get document from the process level global variable 'reviewCycleInput'
DataObject doc = copyService.copy(reviewCycleInput.getDataObject("document"));
myDocumentForReview.set("document",doc);
// get index from onEvent input variable 'myReviewStartRequest'
int i = myReviewStartRequest.getInt("index");
// get the ith user from the 'reviewers' List in 'reviewCycleInput'
List reviewers = reviewCycleInput.getList("reviewers");
type = getVariableType("myReviewResult");
myReviewResult = factory.createByType(type);
String user = (String) reviewers.get(i);
// set the reviewer in the local variable 'myDocumentForRevies'
myDocumentForReview.setString("reviewer", user );
|
清单 2. Java 代码片段 SetResultAndDecrementCounter 的代码
// set the result of this review into the global 'result' variable
List resultList = result.getList("results");
int index = myReviewStartRequest.getInt("index");
resultList.set(index,myReviewResult);
// this review is done --> decrement the number of active reviews
activeReviews = new Integer(activeReviews.intValue() -1 );
|


|
回页首 |
|
通用模式
通过该示例,可得出以下用于并行处理数量不定的实例的通用模式:
问题:流程的一部分需要以并行方式多次执行,而其数量在流程实际运行之前未知。
解决方案:定义包含与事件处理程序关联的范围的一个流程。将要以并行方式执行的该部分业务逻辑放在该事件处理程序内部。
在此范围内,该事件处理程序与以下操作关联:
- 定义设置所需变量的准备活动。尤其是,它将设置一个全局计数器,以对处于活动状态的事件处理程序进行计数;另外,还要设置一个变量,以在列表中保存事件处理程序的结果。
- 定义启动所需数量的事件处理程序的循环。每个事件处理程序都会接收到一个索引作为输入值。
- 在循环之后,定义接收活动,该活动将等待最后一个事件处理程序实例调用。
在事件处理程序内,请确保完成以下事项:
- 进行业务逻辑所要求的处理。使用事件处理程序的索引来从全局输入列表中选择输入值。
- 如果全局范围要求使用事件处理程序的结果,请在全局结果变量中设置该结果。使用事件处理程序的索引来在结果变量列表中选择恰当的 Slot。
- 完成此任务后,对全局计数器进行递减操作(该计数器对活动事件处理程序实例进行计数)。
- 最后,检查全局计数器是否已达到零,如果是,调用主范围中等待的接收活动。


|
回页首 |
|
该模式的变体
可以采用各种方式对上面描述的模式进行修改。可以将其用于实现多种需求,如下所述
- 并行
forEach。 WS-BPEL 2.0 定义了一个 forEach 构造。它允许指定 parallel 属性。如果 parallel 设置为 no,则 forEach 与循环类似。如果 parallel 设置为 yes,则 BPEL 将以并行方式执行循环体的 n 个实例。WebSphere Process Server V6.0 中不支持 forEach 构造。不过,通过使用上面描述的模式,已经可以在 V6 中实现并行 forEach 语义了。
- 从 N 中选择 M。并行
forEach 构造有一个可选功能——completionCondition,可用于在完成所有并行循环实例前终止 forEach 构造。举例来说,假定作者指定了五个审阅人员,但其中三个人进行审阅就足够了。只要有三个审阅人员完成了工作,流程就将终止整个 forEach 构造。
可以对上面描述的模式进行少量的修改来实现此目标。首先,我们必须修改对所有事件处理程序的完成情况进行的检查,以反映只要有三个事件处理程序完成就足够了。其次,在这种情况下,调用主范围内正在等待的接收活动并不够,因为主范围将等待所有运行的事件处理程序完成。在这种情况下,不要调用主范围中的接收活动,而必须在事件处理程序中引发一个错误。此错误将终止该范围和所有正在运行的事件处理程序。为了防止范围将此错误传播到周围的范围和流程,主范围需要一个处理此错误的错误处理程序。此上下文中的错误处理非常简单——只要有自定义错误处理程序存在,就可以防止将错误传播到周围的范围和流程。请注意,主范围中的接收活动仍然需要保持相应的范围为活动状态,即使已不再从此场景中调用它也是如此。
- 具有最后期限的 N 个请求。与上面类似的场景是,需要满足特定的最后期限时。例如,假定作者指定了五个审阅人员;而整个审阅流程必须在特定的时间内完成。可以通过使用
onAlarm 事件处理程序与 onEvent 事件处理程序进行并行处理来对此进行建模。当达到最后期限时,onAlarm 事件处理程序将触发一次。如果流程执行 onAlarm 事件处理程序,它会引发一个错误,以终止当前正在运行的 onEvent 事件处理程序。如果所有 onEvent 事件程序在触发警报前完成,则最后一个 onEvent 事件处理程序将引发一个错误来终止 onAlarm 事件处理程序。同样,为了防止错误传递到周围的范围或流程,主范围需要一个错误处理程序。
- 并行调用的 N 个服务。另一个模式变体处理事件处理程序体中包含的活动。在上面的示例中,事件处理程序包含一项手工任务。但完全可以在事件处理程序中调用任何类型的服务。这可以是 Web 服务、系统组件体系结构(System Component Architecture,SCA)服务或后者的特例——作为 SCA 服务公开的超类。要调用的范围可以公开单向操作,也可以公开请求-响应操作。
- 来自服务的 N 个并行异步应答。假定您希望调用特定数量的单向服务,而这些服务都将调用单向服务进行回调。这可以通过修改上述示例的循环来完成,以便调用活动直接调用外部服务,而不是调用事件处理程序。可以设置事件处理程序来接收来自服务的回调。其余逻辑都保持不变——即,主范围使用接收活动来确定最后一个事件处理程序实例何时发出表示已完成的信号,而事件处理程序体将对计数器进行递减操作。此计数器达到零后,它会向主范围中正在等待的接收活动发送信号,以指示最后一个事件处理程序已完成。
请注意,可以启动包含调用-接收序列的多个事件处理程序实例来处理此场景。如果使用此方法,流程可能会遇到多个接收活动等待相同端口类型和操作的情况。这可能会导致 bpws:conflictingReceive 标准错误。
- 不了解预定义运行时的多个实例。W. van der Aalst 所描述的模式(请参阅参考资料)包含一个称为“MI with no a priori runtime knowledge”的模式。在我们前面的示例中,在实例启动前,实例的数量就已在运行时中定义。在 van der Aalst 的模式中,实际数量只能在启动了一些实例后进行确定。
此模式可以通过使用与上述通用模式略微不同的方法实现。让我们假定事件处理程序的实例检测到必须启动相同事件处理程序的其他实例。该实例必须增加计数器变量,并使用调用活动启动新的事件处理程序实例。这样,主范围内的循环和事件处理程序中的逻辑就可以控制事件处理程序的最终数目。

 |


|
回页首 |
|
结束语
本文对 WS-BPEL 中的事件处理程序进行了说明,并介绍了如何对其进行定义、其所具有的运行时语义以及需要针对 Business Process Choreographer 考虑哪些特别的注意事项。我们介绍了一个建模模式,可供建模人员使用事件处理程序来创建具有数量可变的并行分支的流程,其确切的分支数量只有在运行时才能确定。最后,本文讨论了此模式的一些修改版本和使用情况。 |