简体   繁体   English

Activiti并行服务任务

[英]Activiti parallel Service Tasks

I am trying to implement two service tasks in Activiti that are supposed to run in parallel. 我正在尝试在Activiti中实现两个应该并行运行的服务任务。 The code written below works fine randomly (and interestingly). 下面编写的代码可以随机(且有趣)地正常工作。

What I mean by that is that it occasionally prints only " first " (or " second ") OR it prints two " first " one " second " etc. 我的意思是,它偶尔只打印“ first ”(或“ second ”),或者只打印两个“ first ”(一个)“ second ”(等)。

QUESTION: How can I make these services run in parallel constantly; 问题:如何使这些服务不断并行运行? regardless of the number of services currently running? 不管当前正在运行的服务数量是多少?

PS: When I DELETED activiti:async="true" from the process definition, it only printed " first " or " second ". PS:当我从流程定义中删除activiti:async="true" ,它仅打印“ first ”或“ second ”。 I guess I need that :) 我想我需要:)

Process Definition 工艺定义

<?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> 

Graphical rendering of process definition 流程定义的图形呈现

流程定义的图形呈现

Code for "runThis2" 代码为“ runThis2”

public void runThis2(String test1) throws InterruptedException {            
    while(true)
    {
        Thread.sleep(1000);
        System.out.println(test1);              
    }           
}

Combination of "async" and "exclusive" flags matters “异步”和“排他”标志的组合很重要

It's important to understand how jobs are executed inside the Activiti engine. 了解作业如何在Activiti引擎内执行非常重要。 The following forum thread does a pretty good job describing it: 以下论坛线程在描述它方面做得很好:

https://community.alfresco.com/thread/221453-multiinstance-wont-run-task-in-parallel https://community.alfresco.com/thread/221453-multiinstance-wont-run-task-in-parallel

A key excerpt from one of the original Activiti architects, Tijs Rademakers, on 2013-10-25: Activiti最初的一位建筑师Tijs Rademakers的摘录于2013-10-25:

The parallel gateway and multiinstance constructs are able to run multiple user tasks in parallel for example. 例如,并行网关和多实例构造能够并行运行多个用户任务。 But for service and script tasks they are basically executed serial still. 但是对于服务和脚本任务,它们基本上还是串行执行的。 Async can change this behavior if you also set exclusive to false (the default is true). 如果您还将独占设置为false(默认值为true),则异步可以更改此行为。 Then the job executor will just execute all jobs available and not serially. 然后,作业执行程序将只执行所有可用的作业,而不是顺序执行。 So give it a try to set async to true and exclusive to false. 因此,请尝试将async设置为true,将exclusive设置为false。

Now, by setting activiti:async="true" and activiti:exclusive="false" , what you have effectively done is create a "wait state" in the process by allocating the service tasks (usually processed serially) to the Job Executor. 现在,通过设置activiti:async="true"activiti:exclusive="false" ,您有效完成的工作是通过将服务任务(通常是串行处理)分配给Job Executor来在流程中创建“等待状态”。

But: 但:

  • How many jobs are executed in parallel and 并行执行多少个作业,
  • when they are executed by the Job Scheduler 它们由Job Scheduler执行

is now completely controlled by the Job Executor configuration. 现在完全由Job Executor配置控制。 (Size of thread pool, timeouts, number of concurrent jobs, size of job block are all configurable.) (线程池的大小,超时,并发作业数,作业块的大小都是可配置的。)

Now, this isn't exactly what you expect, meaning, it depends on the size of your job queue, how many jobs are taken in a single sweep and the duration of each job as to when the service tasks will be executed. 现在,这并不完全符合您的期望,这取决于您的作业队列的大小,一次扫描中有多少个作业以及每个作业的执行时间以及执行服务任务的时间。 Meaning, they MIGHT be executed in parallel and they MIGHT be executed serially. 意思是,它们可能并行执行,并且可能串行执行。 Equally, you can't control their order since once again it is on the Job Executor to determine what it does and when. 同样,您无法控制他们的订单,因为再次由求职执行者来决定其工作和时间。

Ok, so assuming this meets your requirement... 好的,假设这符合您的要求...

Optimistic Locking concept 乐观锁概念

...there is still one more issue you may experience (in fact, it is the reason the activiti:exclusive flag was introduced in the first place). ...您可能还会遇到另一个问题(实际上,这是首先引入activiti:exclusive标志的原因)。 On completion of the service tasks, the execution context will be committed to the process instance record in the database as well as to the history records. 服务任务完成后,执行上下文将提交给数据库中的流程实例记录以及历史记录。 Activiti uses "Optimistic Locking" for records for performance purposes. 为了性能起见,Activiti使用“乐观锁定”进行记录。

Now if your process branches complete relatively close to each other in time, then it is possible (actually highly likely) you WILL receive an Optimistic Locking Exception on the DB update, like this: 现在,如果您的进程分支在时间上相对接近彼此完成,那么(实际上很有可能)您将在数据库更新中收到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

(Note: The error above is not actually from Activiti but instead from a project called " Flowable ". However they both had essentially the same codebase as Activiti 6 at the time this question was originally asked. (November 2017).) (注意:上面的错误实际上不是来自Activiti的,而是来自名为“ Flowable ”的项目。但是,在最初提出此问题时,它们两者都具有与Activiti 6相同的代码库。(2017年11月)。)

This will cause the service task to be tagged as FAILED and it will be re-attempted . 这将导致服务任务被标记为FAILED并将被重新尝试 This can be problematic if you are making external calls to SOR (System of Record) or other legacy systems. 如果您要外部调用SOR(记录系统)或其他旧系统,则可能会出现问题。 (Consider what would happen if your flight was actually successfully booked, but the call to reserve it is made a second time because it was perceived to have failed.) (考虑会发生什么,如果你的航班实际上是成功预定,但调用保留它是由第二次,因为它被认为已经失败。)

All good fun stuff and all things that can be resolved with good design and use of best practices. 好的设计和使用的最佳实践可以解决所有好玩的东西。

Hope this helps you understand what is going on. 希望这可以帮助您了解发生了什么。

Greg@BP3 格雷格@ BP3

Further reading 进一步阅读

The Alfresco forums post contains several dead links. Alfresco论坛帖子包含几个无效链接。 Below are live links. 以下是实时链接。

Dead Issue Tracker links 遗留问题跟踪链接

Additional note: Activiti currently (2019) uses neither of those two (codehaus.org or atlassian.net) trackers anymore. 补充说明:Activiti当前(2019)不再使用这两个(codehaus.org或atlassian.net)跟踪器。 Instead they use this GitHub tracker: https://github.com/Activiti/Activiti/issues 相反,他们使用此GitHub跟踪器: https : //github.com/Activiti/Activiti/issues

Dead FAQ link 常见问题解答链接

Activiti flags Activiti标志

Camunda Manual 卡蒙达手册

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM