Using setVariable with activityId

Hi,

I want to set some variables to a specific scope, so I put an execution listener in the start event of my activity and register this java class:

public class InitSequenceDelegate implements ExecutionListener {

    @Override
    public void notify(DelegateExecution execution) throws Exception {
        execution.setVariable("myVar", null, execution.getActivityInstanceId());
    }
}

But, it doesn’t work and give me this error message:

Scope with specified activity Id SubProcess_sequential:10022 and execution 10021 not found

I’ve also tried other DelegateExecution’s methods such as getCurrentCurrentActivity(), getId(), etc to get the right activityId, but still got the same error message

So how do I supposed to get the proper activityId?


NB: I’m following the guide about process variable but I think it’s not clear enough


NB: I’ve also tried to use execution.setVariableLocal(), but that’s not what I want (we can’t set the variable to the parent of the current scope)

Hi @muh.ashlah

Try the following

execution.setVariableLocal("<variable_name>", <variable_value>);

This way the <variable_name> will be defined on the specified execution’s scope.

Please read below link to understand “Variable Scopes and Variable Visibility”

https://docs.camunda.org/manual/7.5/user-guide/process-engine/variables/#variable-scopes-and-variable-visibility

Hi @hassang, thanks for replying

Are you sure about what you’re saying? Because I’ve tried that code inside a subprocess (as a listener) and the variable scope is setted to be process instance scope (not just inside the subprocess). I check it out in the camunda’s cockpit.

By the way, I’m using camunda 7.7 (if the version is matter) and try to follow this guide Process Variables | docs.camunda.org.

There is a possibility to set variables into specific scope from scripts, input\output mapping, listeners and service tasks. Implementation of this functionality is using activity id in order to identify destination scope and will throw an exception if no scope is located to set a variable. Additionally, once target scope is found, variable will be set locally in it, which means that propagation to the parent scope will not be executed even if destination scope does not have a variable with given id.

But I can’t understand how do I get the proper activityId

Please help

Best Regards,
Ashlah

Could you please share a test case on github that reproduces an exception? execution.setVariable("myVar", null, execution.getCurrentActivity().getId()); should work. You can use the unit testing template to get started quickly.

Hi @muh.ashlah
Sorry I have edited my last post…

Try
setVariableLocal instead of setVariable

Hi @thorben,

Sure, but I have to recreate it first. I’ll update when it’s done.

By the way, the DelegateExecution class doesn’t have getCurrentActivity() method, but it have getCurrentActivityId(). Unfortunately, it gave me the same error message

I’ve tried to use the setVariableLocal() method, but that’s not what I want (I’ve explained it on my question).

By the way, thanks for the alternative

Right, that’s the correct API. Sorry for the confusion.

Hi @thorben,

Here’s the example project about this error: https://github.com/hashlash/example-camunda-custom-identity-service

Take a look at src/main/java/example/camunda/delegate/InitLocalVar.java, I register it as an execution listener on the start event inside the subprocess

I’m sorry for the late response

Thanks for providing the code. I reported a bug when using the current activity id, see https://app.camunda.com/jira/browse/CAM-8118. However, in your original post you write that you want to use this with higher scopes, i.e. ancestors of the current activity. Does this work for you?

I’m sorry, I don’t really understand your question. Could you please explain it?

And thanks for reporting it

Let’s say the current activity is a task with id foo and foo is contained in an embedded subprocess with id bar. Then bar is the parent of the current scope, and execution.setVariable("key", "value", "bar") should set the value in the scope of bar. I understood the last line in your original post that this is what you actually want to do, as execution.setVariable("key", "value", "foo") would be equivalent to execution.setVariableLocal("key", "value").

My question is: Does this API work correctly, when you set a variable in a parent scope (or grandparent, etc.) of the current activity?

Oh, I think it’s another problem about the behavior of multi-instance activity (which I want to ask in a new topic).

I want to set a variable for the scope of multi-instance body using setVariableLocal() method at the execution listener. I want to access that variable as the completionCondition of the multi-instance activity

Unfortunately, the variable is created in the scope of the inner activity

The scope that groups all the inner instances has by convention the id <id_of_mi_activity>#multiInstanceBody. So you could try to use that to make a variable available in the scope that groups all the inner activity instances.

2 Likes

Woah, it magically works! But why?

I use the execution.getCurrentActivityId() and append it with #multiInstanceBody string. But when I try without the string appended, it fails. So what is the expected form of activityId?

*as a note, I put that code as an execution listener of a multi-instance activity with event type:start. It’s different with the code I shared which is the listener is the property of a start event of a multi-instance subprocess


Additionally: the activityId need to be unique for activity instance (appended unique number, something like mi_activity#multiInstanceBody:10253)? If not, how do the process engine differ between instances of parallel multi-instance?

I checked on my process instance with camunda cockpit, on variables tab:

  • multi-instance body scope is written with my_activity#multiInstanceBody, but the popping text (when hover the mouse in) shows mi_activity#multiInstanceBody:10253

  • multi-instance inner acticity scope (in my case, it’s a subprocess) is written with SubProcess (SubProce...), and the popping text shows mi_activity:10262

and when I click it, the filter area shows me a criteria with form like this:

Activity Instance ID = mi_activity#multiInstanceBody:10253

We must distinguish between activity ID and activity instance ID here.

Activity ID is the ID of the BPMN element as defined in the XML. This is returned by execution.getCurrentActivityId(). In a process instance, you can have many instances per activity (think about modeling a loop, multi-instance, etc.). That’s why every such instance has an id, the activity instance id accessible via execution.getActivityInstanceId(). Both, activities and activity instances are organized hierarchically according to the BPMN definition.

The setVariable API we are discussing here takes activity IDs as its parameter, not activity instance IDs. When you call setVariable("key", "value", "activityA"), this means that the variable will be set on the next higher instance of activity activityA. This instance is always unique in this context, because there can’t be two parent/grandparent instances of the same activity.

For multi-instance, we have the “magic” activity with ID <actual_activity_id>#multiInstanceBody. This is not represented explicitly in the BPMN XML, but is generated by the process engine. It can be understood like an embedded subprocess that contains the actual activity. This is not something we made up entirely, but somewhat covered by the BPMN specification. See https://blog.camunda.org/post/2015/06/why-we-re-implemented-bpmn-multi/ for details.

Cheers,
Thorben

1 Like

Hi @thorben, thanks for the explanation.

I understand most of your explanation, but I have a little confusion on what you said next higher instance. Could you please explain that?

Let’s say we have a process model like so:

When Task is executed, we have three activity instances organized in a hierarchy:

Process Instance 10 (instance of Process Definition)
                  ^
                  |
Subprocess Instance 11 (instance of Subprocess)
                  ^
                  |
Task Instance 12 (instance of Task)

Assume we call setVariable("key", "value", "Subprocess") API in the context of task instance 12. Then the API traverses the path from instance 12 upwards to the root until it finds an instance of Subprocess and sets the variable there. That’s what I mean with next higher instance. It stops searching once it finds the first such instance, because there cannot be another instance of Subprocess in that path. Of course, the overall tree can have multiple instances of Subprocess, but each path from a leaf to the root can contain at most one such instance.

3 Likes

Oh, now I got it!

But the bug is still valid, right?

Yes, it is. So you get an exception if when you specify the activity ID of the leaf node.