Java Activiti并行服务任务

Java Activiti并行服务任务,java,activiti,Java,Activiti,我试图在Activiti中实现两个应该并行运行的服务任务。下面编写的代码可以随意地工作(而且很有趣) 我的意思是,它偶尔只打印“first”(或“second”)或打印两个“first“one”second”等 问题:如何使这些服务不断并行运行;无论当前运行的服务数量如何 PS:当我从流程定义中删除activiti:async=“true”时,它只打印了“第一个”或“第二个”。我想我需要:) 过程定义 “异步”和“独占”标志的组合很重要 了解作业在Activiti引擎中是如何执行的非常重要。 下

我试图在Activiti中实现两个应该并行运行的服务任务。下面编写的代码可以随意地工作(而且很有趣)

我的意思是,它偶尔只打印“
first
”(或“
second
”)或打印两个“
first
“one”
second
”等

问题:如何使这些服务不断并行运行;无论当前运行的服务数量如何

PS:当我从流程定义中删除
activiti:async=“true”
时,它只打印了“
第一个
”或“
第二个
”。我想我需要:)

过程定义 “异步”和“独占”标志的组合很重要 了解作业在Activiti引擎中是如何执行的非常重要。 下面的论坛帖子很好地描述了这一点:

2013年10月25日,原始Activiti架构师之一Tijs Rademakers的重要摘录:

并行网关和多实例构造能够运行 例如,并行执行多个用户任务。但服务和 脚本任务它们基本上是串行执行的。异步can 如果还将“独占”设置为false(默认值),请更改此行为 是真的)。然后作业执行器将只执行所有可用的作业 而且不是连续的。因此,请尝试将async设置为true和exclusive 这是错误的

现在,通过设置
activiti:async=“true”
activiti:exclusive=“false”
,您有效地做到了将服务任务(通常是串行处理的)分配给作业执行器,从而在流程中创建一个“等待状态”

但是:

  • 并行执行的作业数量以及
  • 当作业调度程序执行它们时
现在完全由作业执行器配置控制。(线程池大小、超时、并发作业数、作业块大小都是可配置的。)

现在,这并不是您所期望的,也就是说,它取决于作业队列的大小、一次扫描中执行的作业数量以及每个作业的持续时间,以及何时执行服务任务。也就是说,它们可以并行执行,也可以串行执行。同样,您也无法控制它们的顺序,因为作业执行者要再次决定它的作用和时间

好的,假设这符合你的要求

乐观锁定概念 …您可能还会遇到另一个问题(事实上,这就是最初引入
activiti:exclusive
标志的原因)。服务任务完成后,执行上下文将提交到数据库中的流程实例记录以及历史记录。出于性能目的,Activiti对记录使用“乐观锁定”

现在,如果您的流程分支在时间上彼此相对接近地完成,那么您将有可能(实际上很可能)在DB更新上收到一个
乐观锁定异常,如下所示:

09:59:52432[flowable-async-job-executor-thread-2]错误org.flowable.job.service.impl.asyncexecutor.DefaultAsyncRunnableExecutionExceptionHandler-作业12575失败
org.flowable.engine.common.api.FlowableOptimisticLockingException:ProcessInstance[12567]被另一个事务同时更新

(注意:上述错误实际上并非来自Activiti,而是来自一个名为“”的项目。然而,在最初提出此问题时,它们的代码库与Activiti 6基本相同。(2017年11月)

这将导致服务任务被标记为失败,并将重新尝试。如果您正在对SOR(记录系统)或其他遗留系统进行外部调用,则可能会出现问题。(考虑一下,如果您的航班实际上已成功预订,但由于被认为已失败而再次拨打预订电话,会发生什么情况。)

所有有趣的东西,以及所有可以通过良好设计和使用最佳实践来解决的事情

希望这能帮助你理解发生了什么

Greg@BP3

进一步阅读 Alfresco论坛帖子包含几个死链接。下面是实时链接

死问题跟踪链接
  • 死亡:=>
    • 活着的:
  • 死亡:=>
    • 活着的:
附加说明:Activiti目前(2019年)不再使用这两个(codehaus.org或atlassian.net)跟踪器。相反,他们使用这个GitHub跟踪器:

死亡常见问题链接
  • 死亡:=>
    • 活着的:
活动旗帜
  • activiti:async
    标志:
  • activiti:exclusive
    标志:
  • 开发人员Joram Barrez对使用async=true和exclusive=false的评论:
卡蒙达手册
  • “Camunda”是另一个“Activiti”分支。因此,两者的技术细节将不完全相同。然而,在Camunda手册中,对交易和“乐观锁定”的概念有一个很好的一般性讨论:

感谢StackzOfZtuff更新死链接。
<?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);              
    }           
}