jBPM jPDL 用户开发手册 3.2.3 - 第15章

15章 异步连续

15.1. 概念

jBPM基于面向图的程序设计(GOP)。基本上,GOP指定一个能够处理并发执行路径的简单状态机。但在执行里算法被指定在GOP中,所有的状态转换在客户端线程的单个操作中完成。如果你不熟悉“第4章 面向图的程序设计”中定义的执行算法,请首先读下。缺省情况下,这个在客户端线程中执行状态转换是一个好的方案,因为它天生适合服务端事务。在一个事务中流程执行从一个等待状态移动到另一个等待状态。
但在某些情况下,一个开发人员可能想在流程定义中微调这个事务划分。在jPDL中,它可能指定流程执行应该使用属性async="true"来继续异步执行。async="true"可以在所有节点类型和所有动作类型中进行指定。

15.2. 示例

正常的情况下,节点总是在令牌(token)进入这个节点后才被执行。所以这个节点是在客户端线程中被执行的。我们将通过看两个例子探讨下异步连续(asynchronous continuations)。第一个例子是有三个节点的流程的一部分。节点'a'是一个等待状态、节点'b'是一个自动步骤而节点'c'也是一个等待状态。这个流程不包含任何的异步行为,它在下面图中被表示。
第一个框中,显示开始情形。令牌指向节点'a',意味着执行路径正等待一个外部的触发。那个触发必须通过给令牌发送一个信号(signal)给定。当信号到达时,令牌将通过节点a传递到节点b。在令牌到达节点b后,节点b被执行。再调用节点b 是一个非等待状态的自动步骤(例如发送邮件)。所以第二个框是节点b被执行时的一个处理快照。既然节点b是流程中的一个自动步骤,那么节点b的执行将包含通过到节点c的转换的令牌传播。节点c是一个等待状态所以第三个框显示了信号方法返回后的最终情形。

Example 1: Process without asynchronous continuation

图 15-1 示例1:无异步连续的流程

尽管持久化在jBPM中并非强制的,但最普遍的情况在事务中调用信号。让我们看下事务的更新。首先,令牌被更新指向节点c。这些更新通过hibernate作为JDBC连接上的GraphSession.saveProcessInstance的结果被生成。其次如果自动动作访问并更新一些资源,那些事务更新应该被组合或成为同一事务的部分。

现在,我们来看下第二个例子,第二个例子是第一的变体而且在节点b中引入了一个异步连续。节点a和节点c同第一个例子相同,即他们还是等待状态。在jPDL中,节点通过设置属性async="true"被标记为异步的。

增加async="true"到节点b的结果是流程执行将被分成两个部分。第一个部分将执行流程到达b点所在处,节点b将被执行。第二部分将执行节点b而且执行将停止在等待状态c上。
事务此后将分裂成两个独立的事务。一个事务为每个部分(One transaction for each part)。当它在第一个事务中要求一个外部触发(Token.signal方法的调用)离开节点a 时,jBPM将自动触发并执行第二个事务。
 
 
 

Example 2: A process with asynchronous continuations

图 15-2 示例2:异步连续流程

对于动作,原理相似。动作使用属性async="true" 标记异步的,被执行流程的外部线程执行。如果持久化配置(这是缺省的),动作将在一个独立的事务中执行。
在jBPM中,异步连续使用异步消息系统被实现。当流程执行到达应该异步执行的一点时,产生一个命令消息并发送它到命令执行器。命令执行器是一个独立的构件,依赖于消息收据,它恢复它获得的挂起的流程执行。
jBPM能够被配置使用JMS provider或内置的异步消息系统。内置的消息系统功能很有限,但是它允许这个特性能够在JMS不可用的环境中被支持。
 

15.3.工作执行器

工作(job)执行器是恢复异步流程执行的构件。它等待工作消息从异步消息系统到达并执行他们。这两个用于异步连续的工作消息是ExecuteNodeJob和ExecuteActionJob。
工作消息被流程执行产生。在流程执行期间,每个节点或执行不得不被异步执行,一个Job(POJO)将被派出到MessageService。消息服务同JbpmContext关联而且它只收集所有不得不被发送的消息。
 
消息将作为JbpmContext.close()的部分被发送。那个方法层叠close()调用到所有的关联服务。这个真正的服务能够在jbpm.cfg.xml中配置。Services、DbMessageService中的一个被缺省的配置而且将通知新工作消息可用的那个工作执行器。

图执行机制使用MessageServiceFactory和MessageService接口发送消息,这个将使异步消息可配置(也在jbpm.cfg.xml中)。在Java EE环境里,DbMessageService能够使用JmsMessageService替换来平衡应用服务器的能力。

这里是执行器如何工作简单地描述:

工作(Jobs)记录在数据库中。Jobs是对象而且也能够被执行。定时器和异步消息都是jobs。对于异步消息,dueDate在他们被插入时简单地设置成当前时间。工作执行器必须执行jobs。这个以2步来完成:

1)              工作执行器线程必须获得一个工作(job)

2)              获得工作(job)的线程必须执行它

获得工作和执行工作以两个独立的事务完成。一个线程通过放它的名称进入工作的所有者域获得工作。每个线程均有唯一的基于ip地址和序号的名称。Hibernate的乐观锁在Job对象上被允许。所以两个线程试图获得一个并发的工作,它们中的一个将得到StaleObjectException异常并回滚。只有第一个将成功。成功获得工作的线程负责在独立的事务中执行它。
一个线程在获得和工作执行期间将死掉。为了在那种情形下进行清理,每工作执行器有一个锁监控线程检查锁时间。被锁的大于30分钟的工作将被解锁以至于他们能够被另一个工作执行。
为了使hibernate的乐观锁正确工作必需的隔离级别应该设置到REPEATABLE_READ。隔离级别将保证

update JBPM_JOB job

set job.version = 2

    job.lockOwner = '192.168.1.3:2'

where

    job.version = 1

在一个恰好竞争的事务中只有一行被更新。
不可重复读( Non-Repeatable Reads 意味着下列的非正常会发生:一个事务重复读取它前面已经读过的数据然而发现数据已经被另一个事务改变了,因为那个事务先前读取的数据已经被另一个提交了。

不可重复读是乐观锁的一个问题因此隔离级别READ_COMMITTED并不足够,它导致允许不可重复读的发生。所以如果你配置了多个工作执行器线程那可重复读(REPEATABLE_READ)是必须的。

 

15.4. jBPM内置异步消息

当使用jBPM内置的异步消息时,工作消息将在持久化他们到数据库前被发送。这个消息持久化能够在和jBPM流程更新一样的相同的transaction/JDBC连接中完成。
工作消息将被存储在JBPM_JOB表中。
POJO命令执行器(org.jbpm.msg.command.CommandExecutor)将从数据库表中读取消息并执行他们。所以典型的POJO命令执行器看起来像这样:
1)读下个命令消息
2)执行命令消息
3)删除命令消息
如果命令执行消息失败,那么事务将回滚。在那之后,一个新的事务将开始增加错误消息到数据库中。命令执行器过滤掉包含一个异常的所有消息。
POJO命令执行器事务

图 15-3 POJO命令执行器事务

如果因为某些原因或其他的,事务增加异常到命令消息将会失败,它也会回滚。那样的话,队列中剩下的没有异常的消息稍后将会重试。
限制:jBPM内置的异常消息系统不支持多节点锁(multinode locking)。所以你不能部署POJO命令器执行多次及让他们配置去使用同相同的数据库。

15.5. 异步架构JMS

异步继续属性,打开了jBPM使用场景的新世界。通常,jBPM用于业务流程建模,它现在能够用于技术技术更高的远景上。

想象下你有一个应用要相当多的异步处理。那样通常情况下很难建立将软件的消息产生和消息消费片绑定在一起。使用jBPM现在建立一个异步架构的整体画面成为可能,让你的所有的代码置入POJO中而且可以在整个流程文件中增加事务划分。jBPM将现在照顾到绑定发送端到接收端而不需要你自己写所有的JMS或MDB代码。

15.6. 属性用法

     将要做的:增加多队列有支持。以便为每个当作异步标记的节点或动作指定一个队列变成可能。它也将循环地为一系列的队列产生大量的消息。因为所有的这一切牡JMS和内置的消息系统应该是可配置的,所以这需要一些如何来做所有这些配置的想法。流程定义不应该必须依赖这两个可能的实现中的任何一个。

 

 

 

 

 oppps, wait

posted it completely!

你可能感兴趣的:(多线程,工作,应用服务器,jms,jbpm)