Hello flowable experts,
We have the requirement in our project to implement a parallel multi-instance call activity.
We make use of the latest fix which introduces the completeAsync attribute to make the completion of the call activity asynchronous (and exclusive).
The fix is introduced in the following commit: fix_1232.
Our scenario is such that even though processes should start in parallel, some processes depend on other processes, therefore they must wait for the processes they depend on to complete their execution in order to proceed.
The initial thought approach, for its simplicity reasons compared to other approaches, is to implement a polling task in the beginning of the called process definition which will in some way poll to check if its dependencies (processes) have completed, and if so, the execution of this specific process instance will proceed. This approach does indeed mean that all process instances are going to be started in parallel, and the requirement which we have to make some processes wait, will be implemented in the process itself, meaning no tweaking of Flowable is required.
Now to the way this polling has been implemented…
Each process (from the call activity) on its completion (in an end process listener) sets a variable TO the root process instance (the process instance which defines the call activity). This variable name is GUARANTEED to be different for every call activity process, meaning that no two call activities will set the same variable to the root process, they are all setting different variables.
The polling step which is at the beginning of the process is aware of what variables it should look for in the root process, therefore this polling step checks for its dependencies (it could depend on multiple processes) by trying to find the specific variable which corresponds to its dependency in the root process. And of course if it is able to find the variable in the root process, then the process which it depends on is indeed completed. This information (the dependant ‘ids’ and the current id) is present in the process via the used activiti:elementVariable which is set from the specific collection. This variable holds the ‘ID’ which is to be used to create a variable (the value of the variable is not important unlike its name) and a list of IDs which to poll for in the beginning. Of course this variable holds more information than that (for the purposes of what the process does) but it just includes those two things required to make this work.
On theory, this sounded like there shouldn’t be any problems and this scenario should work, but then after its implementation, we stumbled across a problem.
We set up a very simple test project which demonstrates the problem we have.
All this project does is start a process which triggers a multi-instance call activity with the described parallel behavior using the fix, and each process instance which is started from the call activity then sets some variable to the root process instance.
Running this specific configuration with, for example 20 parallel call activities, produces some OptimisticLockingException(s) which say “ProcessInstance was updated by another transaction concurrently”. Without setting any variables, this is not reproduced and the processes are able to complete.
So with this having been said, there is the question:
- Why does this happen?
- If this approach is impossible to achieve what we want, what are some approaches you recommend for us, having in mind that one process can depend on MANY other processes (not 1)?
Link to GitHub project which is used for reproducing (includes log.out file which contains the specific logs):
Any help would be greatly appreciated,
Thanks in advance,