cancel
Showing results for 
Search instead for 
Did you mean: 

Multiinstance on callactivity

workflowuser
Champ in-the-making
Champ in-the-making
Hi,

I am trying multi-instance on call activiti and am not able to understand the result. Help appreciated:
I am using ACT-126 code base.

mainwf.bpmn20.xml
==============
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlnsSmiley Surprisedmgdc="http://www.omg.org/spec/DD/20100524/DC" xmlnsSmiley Surprisedmgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
  <process id="MyInstance1" name="MyInstance1">
    <startEvent id="startevent1" name="Start"></startEvent>
    <serviceTask id="servicetask1" name="Service Task A" activiti:class="com.activiti.tasks.ADelegate"></serviceTask>
    <serviceTask id="servicetask2" name="Service Task B" activiti:class="com.activiti.tasks.BDelegate"></serviceTask>
    <callActivity id="callactivity1" name="Call activity" calledElement="CallAct1" activiti:async="true">
      <multiInstanceLoopCharacteristics isSequential="false">
        <loopCardinality>4</loopCardinality>
      </multiInstanceLoopCharacteristics>
    </callActivity>
    <serviceTask id="servicetask3" name="Service Task C" activiti:class="com.activiti.tasks.CDelegate"></serviceTask>
    <endEvent id="endevent1" name="End"></endEvent>
    <sequenceFlow id="flow1" name="" sourceRef="startevent1" targetRef="servicetask1"></sequenceFlow>
    <sequenceFlow id="flow2" name="" sourceRef="servicetask1" targetRef="servicetask2"></sequenceFlow>
    <sequenceFlow id="flow3" name="" sourceRef="servicetask2" targetRef="callactivity1"></sequenceFlow>
    <sequenceFlow id="flow4" name="" sourceRef="callactivity1" targetRef="servicetask3"></sequenceFlow>
    <sequenceFlow id="flow5" name="" sourceRef="servicetask3" targetRef="endevent1"></sequenceFlow>
  </process>
 
</definitions>

CallAct1.bpmn20.xml:
================
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlnsSmiley Surprisedmgdc="http://www.omg.org/spec/DD/20100524/DC" xmlnsSmiley Surprisedmgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
  <process id="CallAct1" name="CallAct1">
    <startEvent id="startevent1" name="Start"></startEvent>
    <serviceTask id="servicetask1" name="Service Task X" activiti:class="com.activiti.tasks.XDelegate"></serviceTask>
    <serviceTask id="servicetask2" name="Service Task Y" activiti:class="com.activiti.tasks.YDelegate"></serviceTask>
    <serviceTask id="servicetask3" name="Service Task Z" activiti:class="com.activiti.tasks.ZDelegate"></serviceTask>
    <endEvent id="endevent1" name="End"></endEvent>
    <sequenceFlow id="flow1" name="" sourceRef="startevent1" targetRef="servicetask1"></sequenceFlow>
    <sequenceFlow id="flow2" name="" sourceRef="servicetask1" targetRef="servicetask2"></sequenceFlow>
    <sequenceFlow id="flow3" name="" sourceRef="servicetask2" targetRef="servicetask3"></sequenceFlow>
    <sequenceFlow id="flow4" name="" sourceRef="servicetask3" targetRef="endevent1"></sequenceFlow>
  </process> 
</definitions>

I expect callactivity1 4 instances to be picked up concurrently. The execution, however, is happening sequentially (main thread executes both main and call activiti instances).

thanks
4 REPLIES 4

trademak
Star Contributor
Star Contributor
Hi,

By default Activiti executes automatic tasks like a service task and a call activity in the same transaction.
That's also true when you use a multi instance construct. So even if you set sequential to false, the multi instance in your example will execute sequential.
There are 2 "solutions" to this. You can add a non-automatic task, like a receive task or a user task. This will cause the transaction to be committed and a new multi instance item will be processed.
Or you can use the asynchronous continuation functionality that's available in trunk and in a few days in 5.8 on one of the service tasks so that the transaction will be committed and a new multi instance item will be processed.

Best regards,

workflowuser
Champ in-the-making
Champ in-the-making
Hi,

Thank you for your reply.
Just to clarify:
<callActivity id="callactivity1" name="Call activity" calledElement="CallAct1" activiti:async="true">

async continuation on call activity level works only if one of the task (should it be the first task?) is receive or user task?

I would like to run each instance of call activity sequentially but across instances parallel. In your option 2, if I specify async continuation on the first script task in embedded call-activity, would it do that?

CallAct1.bpmn20.xml:
================
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlnsSmiley Surprisedmgdc="http://www.omg.org/spec/DD/20100524/DC" xmlnsSmiley Surprisedmgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
<process id="CallAct1" name="CallAct1">
<startEvent id="startevent1" name="Start"></startEvent>
<serviceTask id="servicetask1" name="Service Task X" activiti:class="com.activiti.tasks.XDelegate" async="true"></serviceTask>
<serviceTask id="servicetask2" name="Service Task Y" activiti:class="com.activiti.tasks.YDelegate"></serviceTask>
<serviceTask id="servicetask3" name="Service Task Z" activiti:class="com.activiti.tasks.ZDelegate"></serviceTask>
<endEvent id="endevent1" name="End"></endEvent>
<sequenceFlow id="flow1" name="" sourceRef="startevent1" targetRef="servicetask1"></sequenceFlow>
<sequenceFlow id="flow2" name="" sourceRef="servicetask1" targetRef="servicetask2"></sequenceFlow>
<sequenceFlow id="flow3" name="" sourceRef="servicetask2" targetRef="servicetask3"></sequenceFlow>
<sequenceFlow id="flow4" name="" sourceRef="servicetask3" targetRef="endevent1"></sequenceFlow>
</process>
</definitions>

Hi,

By default Activiti executes automatic tasks like a service task and a call activity in the same transaction.
That's also true when you use a multi instance construct. So even if you set sequential to false, the multi instance in your example will execute sequential.
There are 2 "solutions" to this. You can add a non-automatic task, like a receive task or a user task. This will cause the transaction to be committed and a new multi instance item will be processed.
Or you can use the asynchronous continuation functionality that's available in trunk and in a few days in 5.8 on one of the service tasks so that the transaction will be committed and a new multi instance item will be processed.

Best regards,

malulish
Champ in-the-making
Champ in-the-making
Hi,

I have the very same need. Did you solve by your own the issue? If yes, could you please say how?

thanks

araghuraman
Champ in-the-making
Champ in-the-making
I am currently using the following workaround in cases where a process uses multiinstance callactivity or sub-process in the main process and need to get hold of all the results from the called processes:

    1) Encapsulate all input parameters to your callactivity or subprocess in a Java POJO. Have two additional fields: resultKeyVariable (String) and callerExecutionId (String) in the POJO.
    resultKeyVariable field will contain a "key" unique to each execution of callactivity called in loop.
    activiti:collection will be set to a list of such POJOs lets call it "myInputCollection".
    So each elementVariable is this POJO instance, lets call it eachInput.
    activity:in="eachInput"

    Elsewhere in code before you call multiinstance activity:
    ArrayList<EachInputClass> myInputCollection = new ArrayList<EachInputClass>()

    EachInputClass eachInput1 = new EachInput();
    eachInput1.email = "jb@mymail.com";
    eachInput1.username = "jimbarnes";
    eachInput1.resultKeyVariable = "emailsendresult_jbatmymaildotcom_jimbarnes";
    eachInput.callerExecutionId = execution.getId();
    //next one
    EachInputClass eachInput2 = new EachInput();
    eachInput2.username = "raghuraman@mymail.com";
    eachInput2.username = "ragu";
    eacchInput2.resultKeyVariable = "emailsendresult_raghuramanatmymaildotcom_ragu";

    execution.setVariable("myInputCollection",myInputCollection);

    finally, in the bpmn xml:

         <extensionElements>
          <activiti:in source="eachInput" target="eachInput"/>
         </extensionElements>
       <multiInstanceLoopCharacteristics isSequential="false" activiti:collection="myInputCollection" activiti:elementVariable="eachInput"/>



    2) In the sub process or called activity, retrieve the input POJO which we will call "eachInput" , finish your logic and then finally, before the end event, insert an additional JavaDelegate, which does the following

    Object myresult == ..//my results
    String resultKeyVariable = (String) eachInput.resultKeyVariable;
    String callerExecutionId = (String) eachInput.callerExecutionId;
    runtimeService.setVariable(callerExecutionId, resultKeyVariable,myresult);

    3) In the calling process after all the callactivities are done, retrieve the results thus:

    for(Object each: myInputCollection)
    {
       Object myresult = (Object)   execution.getVariable(each.resultKeyVariable);
       …
    }