由于业务要求的原因,我们的工作流系统所做的工作大部分是调用各种各样的程序,不需要人工参与,所以在流程中,除功能节点(指START-STATE,END-State,Fork,Join,Decision)外,业务逻辑全放在NODE节点的ACTION中来实现。
public class DemoActionHandler implements ActionHandler {
/**
* 简单的ACTIONHANDLER DEMO
*/
private static final long serialVersionUID = 1L;
@SuppressWarnings("unchecked")
@Override
public void execute(ExecutionContext executionContext) throws Exception {
Node node = executionContext.getNode();
System.out.print(executionContext.getProcessInstance().getId());
System.out.println("--[" + node.getName() + "] ["
+ new java.util.Date()+"]");
ContextInstance cxtInstance = executionContext.getProcessInstance()
.getContextInstance();
try {
Date date = new Date();
Date startDate = (Date) cxtInstance.getVariable("STARTDATE");
System.out.println("执行到此节点共用时:" + ""
+ (date.getTime() - startDate.getTime()));
} catch (Exception e) {
e.printStackTrace();
}
Thread.sleep(6000);
node.leave(executionContext);
}
}
我写了一个简单的流程,串行的,不包含分支,只包含开始,结束,NODE三种类型的节点。将流程发布,创建实例 ,在实例启动后用轮询的方式查询跟踪token所在的位置(如果有分支的情况下可能需要考虑子token的情况),发现个流程的监控结果只有两个结点:START和END,这是为什么呢,首先想到的是流程实例的状态并没有实时的保存或是说持久化到数据库中去。
再结合自己的程序想了一下,程序中的节点全部是NODE类型的自动节点,流程在执行的时候,会直到一个等待节点才将流程实例持久化到数据库中。但如果将NODE节点的async(异步执行)属性设置的true,流程会在执行到该节点时,会启动一个线程来执行NODE的ACTIONHANDLER,而TOKEN本身会挂起,等待执行完毕的消息,事务因此也将由一个被分裂为两个独立的事务.也就是说,原来从开始执行到等待状态为止的一个事务被异步节点分了成多个事务,流程会在执行异步节点的ACTIONHANDLER时将事务提交,流程实例的状态也就会持久化到数据库中去。
于是加上
node.setAsync(true);
这样就OK了。
接着测试有分支的情况,又发现fork下的节点是依次执行的,查了资料,有如下的说法
引用
fork的底层其实是依次调用各个transition,而不是真正意义的同步,如果需要同步,请参考JBPM异步设置
于是把FORK节点的async属性也设置成了true,测试后发现还是不行。按照上面的说法,fork在执行各个分支的时候,采用了类似遍历的方式调用各个分支,但不至于非得执行完成一个分支后再执行另一个分支。无奈放下了,开始查找资料,这部分工作也是因此搁浅了将近一天的时间。晚上在家查阅资料的时候,发现有人提起了JobExecutor的线程个数,我觉得有可能这个的原因。翻下源码,找了个API试验一下
jobExecutor = jbpmConfiguration.getJobExecutor();
jobExecutor.setNbrOfThreads(5);
jobExecutor.start();
结果喜剧了,我惊喜的发现,fork下的节点竟然同步执行了(当然同步的执行也会有先后)。
虽然这本来就是fork节点的基本作用,但实际用起来的时候还是会遇到各种战利品样的问题。原因就在这里,如果不设置其线程数,JobExecutor默认启动一个线程为工作,这样就导致fork下的节点进入了队列,结果就是串行执行了。
OK,本文完。