Confuse on the multi-instance variables

I know the document said that variables in subflow of multi-instance are only be seen at current/child scope. however, i find it is propagated to parent scope? it is a bug?

and

I am sure the varaible gitlabProjectId will be set in the subflow

what is the root cause?

camunda/zeebe:0.23.1
camunda/operate:0.23.0

thanks

Hi @aximo,

you need to share more information about your example.

Where is the variable gitlabProjectId set?
Do you define any variable mapping?

From the BPMN, it seems that the variable could be provided by the task “find the gitlab project id” that is inside the multi-instance subprocess.

If the variable gitlabProjectId is provided the task then it must be defined previously in the input mappings of the subprocess. Otherwise, it is propagated to the workflow instance (root) scope and visible to the whole instance.

Please have a look at the docs: https://docs.zeebe.io/bpmn-workflows/multi-instance/multi-instance.html#variable-mappings

Does this help you?

Best regards,
Philipp

hi, @philipp.ossler thanks your quickly reply

Where is the variable gitlabProjectId set?
Do you define any variable mapping?

From the BPMN, it seems that the variable could be provided by the task “find the gitlab project id” that is inside the multi-instance subprocess.

yes, the gitlabProjectId variable is set in the task named “find the gitlab project id”, in this task , i am not define any output mapping.

If the variable gitlabProjectId is provided the task then it must be defined previously in the input mappings of the subprocess. Otherwise, it is propagated to the workflow instance (root) scope and visible to the whole instance.

sorry, I am not understand your meaning, welcome if more detail.
I read the document and guess that your meaning is that:

by default,  the variable which set in job will be seems in whole workflow instance and other subflow of multi instance.

is it right?

I also see that If a variable is defined as local variable, then it is not propagated to a parent or the workflow instance scope and can't be modified outside of the instance, so, the question is, what is the exactly meaning of define a local variable? you know, there are two ways to create variable, one is via zeebe client sdk and another is output mapping, which one is the way to create “local variable”?

A local variable is only visible within its scope and its child scopes (e.g. a subprocess).

A local variable is usually created by defining it via input mapping (e.g. on a subprocess).

A local variable is often used to prevent that a variable is propagated to the workflow instance (root) scope and visible to other activities.

The input mappings can be used to create new local variables in the scope of an instance. These variables are only visible within the instance. It is a way to restrict the visibility of variables. By default, new variables (e.g. provided by a job worker) are created in the scope of the workflow instance and are visible to all instances of the multi-instance activity as well as outside of it. In case of a parallel multi-instance activity, this can lead to variables that are modified by multiple instances and result in race conditions. If a variable is defined as local variable, then it is not propagated to a parent or the workflow instance scope and can’t be modified outside of the instance.

Does this answer your question?

Sorry, i still very confusion according my invest.
I create mock process to research the variable issue, the process is

<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:zeebe="http://camunda.org/schema/zeebe/1.0" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_10gb0at" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Zeebe Modeler" exporterVersion="0.9.1">
  <bpmn:process id="mock-process" isExecutable="true">
    <bpmn:startEvent id="StartEvent_1">
      <bpmn:outgoing>Flow_0ulicn4</bpmn:outgoing>
    </bpmn:startEvent>
    <bpmn:sequenceFlow id="Flow_0ulicn4" sourceRef="StartEvent_1" targetRef="Activity_1kujh3x" />
    <bpmn:endEvent id="Event_12hj9nh">
      <bpmn:incoming>Flow_0reym0t</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:serviceTask id="Activity_1kujh3x" name="just a mock">
      <bpmn:extensionElements>
        <zeebe:taskDefinition type="MockCommand" />
      </bpmn:extensionElements>
      <bpmn:incoming>Flow_0ulicn4</bpmn:incoming>
      <bpmn:outgoing>Flow_17a0th4</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:subProcess id="Activity_0hl51m6">
      <bpmn:incoming>Flow_17a0th4</bpmn:incoming>
      <bpmn:outgoing>Flow_0reym0t</bpmn:outgoing>
      <bpmn:multiInstanceLoopCharacteristics>
        <bpmn:extensionElements>
          <zeebe:loopCharacteristics inputCollection="= services" inputElement="service" outputCollection="statuses" outputElement="=status" />
        </bpmn:extensionElements>
      </bpmn:multiInstanceLoopCharacteristics>
      <bpmn:startEvent id="Event_1nezna4">
        <bpmn:outgoing>Flow_058vll4</bpmn:outgoing>
      </bpmn:startEvent>
      <bpmn:serviceTask id="Activity_0b9uo84" name="check the service status">
        <bpmn:extensionElements>
          <zeebe:taskDefinition type="MockShowNameCommand" />
        </bpmn:extensionElements>
        <bpmn:incoming>Flow_058vll4</bpmn:incoming>
        <bpmn:outgoing>Flow_06lzh3u</bpmn:outgoing>
      </bpmn:serviceTask>
      <bpmn:sequenceFlow id="Flow_058vll4" sourceRef="Event_1nezna4" targetRef="Activity_0b9uo84" />
      <bpmn:endEvent id="Event_0uyp356">
        <bpmn:incoming>Flow_1xpzmsj</bpmn:incoming>
      </bpmn:endEvent>
      <bpmn:sequenceFlow id="Flow_06lzh3u" sourceRef="Activity_0b9uo84" targetRef="Activity_1ezxom9" />
      <bpmn:serviceTask id="Activity_1ezxom9" name="show All variables">
        <bpmn:extensionElements>
          <zeebe:taskDefinition type="DebugCommand" />
        </bpmn:extensionElements>
        <bpmn:incoming>Flow_06lzh3u</bpmn:incoming>
        <bpmn:outgoing>Flow_1xpzmsj</bpmn:outgoing>
      </bpmn:serviceTask>
      <bpmn:sequenceFlow id="Flow_1xpzmsj" sourceRef="Activity_1ezxom9" targetRef="Event_0uyp356" />
    </bpmn:subProcess>
    <bpmn:sequenceFlow id="Flow_17a0th4" sourceRef="Activity_1kujh3x" targetRef="Activity_0hl51m6" />
    <bpmn:sequenceFlow id="Flow_0reym0t" sourceRef="Activity_0hl51m6" targetRef="Event_12hj9nh" />
  </bpmn:process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="mock-process">
      <bpmndi:BPMNEdge id="Flow_0ulicn4_di" bpmnElement="Flow_0ulicn4">
        <di:waypoint x="188" y="180" />
        <di:waypoint x="240" y="180" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_17a0th4_di" bpmnElement="Flow_17a0th4">
        <di:waypoint x="340" y="180" />
        <di:waypoint x="400" y="180" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_0reym0t_di" bpmnElement="Flow_0reym0t">
        <di:waypoint x="1040" y="180" />
        <di:waypoint x="1142" y="180" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="Activity_1h65wqt_di" bpmnElement="Activity_1kujh3x">
        <dc:Bounds x="240" y="140" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
        <dc:Bounds x="152" y="162" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Event_12hj9nh_di" bpmnElement="Event_12hj9nh">
        <dc:Bounds x="1142" y="162" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Activity_0hl51m6_di" bpmnElement="Activity_0hl51m6" isExpanded="true">
        <dc:Bounds x="400" y="80" width="640" height="200" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="Flow_058vll4_di" bpmnElement="Flow_058vll4">
        <di:waypoint x="476" y="180" />
        <di:waypoint x="510" y="180" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_06lzh3u_di" bpmnElement="Flow_06lzh3u">
        <di:waypoint x="610" y="180" />
        <di:waypoint x="710" y="180" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_1xpzmsj_di" bpmnElement="Flow_1xpzmsj">
        <di:waypoint x="810" y="180" />
        <di:waypoint x="952" y="180" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="Event_1nezna4_di" bpmnElement="Event_1nezna4">
        <dc:Bounds x="440" y="162" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Event_0uyp356_di" bpmnElement="Event_0uyp356">
        <dc:Bounds x="952" y="162" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Activity_1k3pmb9_di" bpmnElement="Activity_0b9uo84">
        <dc:Bounds x="510" y="140" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Activity_1ezxom9_di" bpmnElement="Activity_1ezxom9">
        <dc:Bounds x="710" y="140" width="100" height="80" />
      </bpmndi:BPMNShape>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</bpmn:definitions>

then i start the process the via

curl --location --request POST 'http://localhost:9999/workflows/start' \
--header 'Content-Type: application/json' \
--data-raw '{
	"processDefinitionId":"mock-process",
	"variables": {
		"name": "shawn01",
		"services": ["1a","2a","3a","4a"]
	}
}'

the MockShowNameCommand will get current nano time and set to variable named currentTime

then i check my logs:

2020-05-27 14:21:46.029  INFO 66694 --- [ult-executor-74] io.zeebe.client.job.poller               : Activated 1 jobs for worker default and job type MockCommand
2020-05-27 14:21:46.029  INFO 66694 --- [pool-2-thread-3] c.a.a.r.m.zeebe.BusinessJobWrap          : begin to process the job MockCommand
2020-05-27 14:21:46.030  INFO 66694 --- [pool-2-thread-3] c.a.a.r.middleware.zeebe.MockCommand     : success run the job with name shawn01
2020-05-27 14:21:46.645  INFO 66694 --- [pool-2-thread-5] c.a.a.r.m.zeebe.BusinessJobWrap          : begin to process the job MockShowNameCommand
2020-05-27 14:21:46.645  INFO 66694 --- [pool-2-thread-3] c.a.a.r.m.zeebe.BusinessJobWrap          : begin to process the job MockShowNameCommand
2020-05-27 14:21:46.645  INFO 66694 --- [pool-2-thread-4] c.a.a.r.m.zeebe.BusinessJobWrap          : begin to process the job MockShowNameCommand
2020-05-27 14:21:46.645  INFO 66694 --- [ult-executor-74] io.zeebe.client.job.poller               : Activated 4 jobs for worker default and job type MockShowNameCommand
2020-05-27 14:21:46.645  INFO 66694 --- [pool-2-thread-1] c.a.a.r.m.zeebe.BusinessJobWrap          : begin to process the job MockShowNameCommand
2020-05-27 14:21:46.646  INFO 66694 --- [pool-2-thread-3] c.a.a.r.m.zeebe.MockShowNameCommand      : the service 2a with the currentTime 2624074564564357
2020-05-27 14:21:46.646  INFO 66694 --- [pool-2-thread-4] c.a.a.r.m.zeebe.MockShowNameCommand      : the service 4a with the currentTime 2624074564568426
2020-05-27 14:21:46.646  INFO 66694 --- [pool-2-thread-1] c.a.a.r.m.zeebe.MockShowNameCommand      : the service 3a with the currentTime 2624074564580008
2020-05-27 14:21:46.646  INFO 66694 --- [pool-2-thread-5] c.a.a.r.m.zeebe.MockShowNameCommand      : the service 1a with the currentTime 2624074564564389
2020-05-27 14:21:47.129  INFO 66694 --- [pool-2-thread-5] c.a.a.r.m.zeebe.BusinessJobWrap          : begin to process the job DebugCommand
2020-05-27 14:21:47.129  INFO 66694 --- [ult-executor-86] io.zeebe.client.job.poller               : Activated 4 jobs for worker default and job type DebugCommand
2020-05-27 14:21:47.129  INFO 66694 --- [pool-2-thread-4] c.a.a.r.m.zeebe.BusinessJobWrap          : begin to process the job DebugCommand
2020-05-27 14:21:47.129  INFO 66694 --- [pool-2-thread-3] c.a.a.r.m.zeebe.BusinessJobWrap          : begin to process the job DebugCommand
2020-05-27 14:21:47.129  INFO 66694 --- [pool-2-thread-2] c.a.a.r.m.zeebe.BusinessJobWrap          : begin to process the job DebugCommand
2020-05-27 14:21:47.129  INFO 66694 --- [pool-2-thread-4] c.a.a.r.m.zeebe.BusinessContext          : the variables are {"status":true,"service":"4a","loopCounter":4,"statuses":[null,null,null,null],"name":"shawn01","time":"2020-05-27 14:21:46","services":["1a","2a","3a","4a"],"currentTime":2624074564564357}
2020-05-27 14:21:47.129  INFO 66694 --- [pool-2-thread-2] c.a.a.r.m.zeebe.BusinessContext          : the variables are {"status":true,"service":"2a","loopCounter":2,"statuses":[null,null,null,null],"name":"shawn01","time":"2020-05-27 14:21:46","services":["1a","2a","3a","4a"],"currentTime":2624074564564357}
2020-05-27 14:21:47.129  INFO 66694 --- [pool-2-thread-4] c.a.a.r.middleware.zeebe.DebugCommand    : debug the command
2020-05-27 14:21:47.129  INFO 66694 --- [pool-2-thread-3] c.a.a.r.m.zeebe.BusinessContext          : the variables are {"status":true,"service":"1a","loopCounter":1,"statuses":[null,null,null,null],"name":"shawn01","time":"2020-05-27 14:21:46","services":["1a","2a","3a","4a"],"currentTime":2624074564564357}
2020-05-27 14:21:47.129  INFO 66694 --- [pool-2-thread-5] c.a.a.r.m.zeebe.BusinessContext          : the variables are {"status":true,"service":"3a","loopCounter":3,"statuses":[null,null,null,null],"name":"shawn01","time":"2020-05-27 14:21:46","services":["1a","2a","3a","4a"],"currentTime":2624074564564357}
2020-05-27 14:21:47.129  INFO 66694 --- [pool-2-thread-2] c.a.a.r.middleware.zeebe.DebugCommand    : debug the command
2020-05-27 14:21:47.129  INFO 66694 --- [pool-2-thread-3] c.a.a.r.middleware.zeebe.DebugCommand    : debug the command
2020-05-27 14:21:47.129  INFO 66694 --- [pool-2-thread-5] c.a.a.r.middleware.zeebe.DebugCommand    : debug the command

I real don’t understand why the variables in currentTime inshow all variables job are all same. it should be different

And, how to reference the different currentTime in sub flow in this case?

thanks

Nope. According to your workflow, this behavior is correct.

If you check the variables then you should see that the variable currentTime is set on the workflow instance scope.

It is set on the workflow instance scope because the variable is not defined previously in any scope.

In order to limit the visibility of the variable, it must be defined (i.e. initialized) in the input mapping of the subprocess. For example, source: =null target: currentTime.

1 Like

it ok now, thanks very much.

maybe this should be in the document page, i think many people will make mistake about variable scope at here as it is so counter-intuitively

btw, i want to know why not let the variable stay at current scope ,and after current scope stop/finish, then propagated to parent scope?

The behavior is documented here:

Feel free to open a PR if you have a suggestion on how to improve the docs.

We chose this approach based on our experience with Camunda BPM. In Camunda BPM the variable visibility and propagation works the same: Process Variables | docs.camunda.org