我正在尝试在Activiti中实现两个应该并行运行的服务任务。下面编写的代码随机(并且有趣)工作得很好。
我的意思是偶尔会打印“first
”(或“second
”)或打印两个“first
”一个“second
”等
问题:如何让这些服务不断并行运行;无论当前运行的服务数量是多少?
PS:当我从流程定义中删除activiti:async="true"
时,它只会打印“first
”或“second
”。我想我需要:)
<?xml version='1.0' encoding='UTF-8'?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:activiti="http://activiti.org/bpmn" targetNamespace="Examples">
<process id='testparallelact' name="Developer Hiring" isExecutable="true" activiti:exclusive="false" activiti:async="true">
<startEvent id="theStart" />
<sequenceFlow id="flow1" sourceRef="theStart" targetRef="fork" />
<parallelGateway id="fork" activiti:async="true" />
<sequenceFlow sourceRef="fork" targetRef="receivePayment" />
<sequenceFlow sourceRef="fork" targetRef="shipOrder" />
<serviceTask id="receivePayment" name="Receive Payment" activiti:async="true" activiti:exclusive="false"
activiti:expression="${serviceConnections.runThis2('First')}"/>
<sequenceFlow sourceRef="receivePayment" targetRef="join" />
<serviceTask id="shipOrder" name="Ship Order" activiti:async="true" activiti:exclusive="false"
activiti:expression="${serviceConnections.runThis2('Second')}"/>
<sequenceFlow sourceRef="shipOrder" targetRef="join" />
<parallelGateway id="join" />
<sequenceFlow sourceRef="join" targetRef="theEnd" />
<endEvent id="theEnd" />
</process>
</definitions>
public void runThis2(String test1) throws InterruptedException {
while(true)
{
Thread.sleep(1000);
System.out.println(test1);
}
}
答案 0 :(得分:3)
了解如何在Activiti引擎内执行作业非常重要。 以下论坛帖子可以很好地描述它:
https://community.alfresco.com/thread/221453-multiinstance-wont-run-task-in-parallel
2013-10-25,来自最初的Activiti建筑师之一Tijs Rademakers的重要摘录:
并行网关和多实例构造能够运行 例如,并行多个用户任务。但是对于服务和 脚本任务基本上仍然是串行执行的。异步可以 如果您还将exclusive设置为false(默认值,则更改此行为) 是真的)。然后,作业执行程序将执行所有可用的作业 而不是连续的。因此,尝试将异步设置为true和exclusive 为假。
现在,通过设置activiti:async="true"
和activiti:exclusive="false"
,您实际完成的是创建一个&#34;等待状态&#34;在此过程中,通过将服务任务(通常以串行方式处理)分配给Job Executor。
可是:
现在完全由Job Executor配置控制。 (线程池的大小,超时,并发作业的数量,作业块的大小都是可配置的。)
现在,这并不完全符合您的预期,这意味着,这取决于作业队列的大小,单次扫描中的作业数量以及每项作业的持续时间以及服务任务的时间被执行。意思是,它们可以并行执行,它们可以连续执行。同样,您无法控制他们的订单,因为Job Executor会再次确定它的作用和时间。
好的,假设这符合您的要求......
...您可能还会遇到另外一个问题(实际上,这是首先引入activiti:exclusive
标志的原因)。完成服务任务后,执行上下文将提交到数据库中的流程实例记录以及历史记录。 Activiti使用&#34;乐观锁定&#34; 作为性能目的的记录。
现在,如果您的流程分支在时间上彼此相对接近完成,则可能(实际上很有可能)您将在数据库更新中收到Optimistic Locking Exception
,如下所示:
09:59:52,432 [flowable-async-job-executor-thread-2] ERROR org.flowable.job.service.impl.asyncexecutor.DefaultAsyncRunnableExecutionExceptionHandler - Job 12575 failed org.flowable.engine.common.api.FlowableOptimisticLockingException: ProcessInstance[12567] was updated by another transaction concurrently
(注意:上面的错误实际上不是来自Activiti,而是来自一个名为&#34; Flowable&#34;的项目。但是它们与Activiti 6的代码库基本相同最初问这个问题的时间。(2017年11月)。)
这将导致服务任务被标记为FAILED,并且重新尝试。如果要对SOR(记录系统)或其他遗留系统进行外部调用,则可能会出现问题。 (考虑如果您的航班实际成功预订会发生什么,但是保留的呼叫是第二次,因为它被认为已经失败。)
所有好玩的东西和所有可以通过良好的设计和使用最佳实践来解决的事情。
希望这可以帮助您了解正在发生的事情。
格雷格@ BP3
Alfresco论坛帖子包含几个死链接。以下是实时链接。
附加说明:Activiti目前(2019)不再使用这两个(codehaus.org或atlassian.net)跟踪器。相反,他们使用此GitHub跟踪器:https://github.com/Activiti/Activiti/issues
activiti:async
旗帜:https://www.activiti.org/userguide/#asyncContinuations activiti:exclusive
旗帜:https://www.activiti.org/userguide/#exclusiveJobs