From this picture: two inclusive gateways defined namely, “fork” and “join”
Let’s say both the outgoing sequence conditions are evaluated to true, and two tokens will arrive at “join” inclusive gateway. Here, if the token of sequence flow of ship order reached earlier than the “receive payment” token, let’s say 10 minutes interval between two tokens to arrive at “join” inclusive gateway, then how long the “join” inclusive gateway will wait for the token from receive payment outgoing sequence flow?
How could the “join” inclusive gateway is aware of, that needs to be waited for how many tokens need to be received in order to trigger “join” gateway execution?
If one of the outgoing sequence flow condition is evaluated as false, then how could the “join” inclusive gateway aware that it will trigger the gateway execution after receiving only 1 token for which the outgoing sequence flow condition is evaluated to true?
The “fork” inclusive gateway will send some signal to “join” inclusive gateway, that how many tokens it will receive based on outgoing sequence flows chosen for execution from “fork” inclusive gateway?
Without being completely familiar with the internal workings, here are some answers to your questions:
- Indefinitely. The gateway will wait as long as it takes for all tokens to arrive.
- It’s not something you have to model or configure yourself. Camunda takes care of it for you. It basically knows about all of the Executions that were created when the fork gateway was activated and can check whether all of them have now reached the join gateway to know when to continue out of the gateway.
- See 2. It doesn’t matter how many paths were taken, it knows.
- See 2. The other way around: the join can lookup what to expect and conclude what to do, each time a token reaches it.
I try to understand how the inclusive Join works and came across this thread. The answers are a bit vague IMO (“it knows”).
Isn’t it an undecidable problem whether a token will arrive via the specified connection?
And hence: isn’t it undecidable whether an inclusive join has to wait for the token arriving via it?
And hence: shouldn’t inclusive joins be avoided at all as their behaviour is not very clear?
When would one want to use them?
Such problems do not exist for inclusive forks.
Thanks for your thoughts!
you can and should use it if you avoid process models like this:
When by chance a token gets removed before the joining gateway, the process instance will be stucked here forever.
Inclusive gateways makes the models easier to understand than combinations of exclusive and parallel gateways.
Hope this helps, Ingo
Thank you @Ingo_Richtsmeier for the quick reply.
But why? Why would the process engine know that it has to wait until two tokens arrive (and not just one)? Is there some “correlation” between the fork and the join? In the sense that the join “knows” to which fork it “belongs” and hence knows how many branches have been activated by the fork?
An inclusive join can be placed anywhere in the process model; there is not necessarily a “corresponding” fork. How does the engine then know what tokens to wait for?
Could you please explain why this model is “bad”? I once again looked into the spec of the BPMN. When Task1 is excuted (in the upper branch), and the exclusive fork is evaluated so that Task3 is executed, then the inclusive join should be activated IMO. But you say that the process will be stuck. Why?
After Task3 has been executed, the condition for activating the inclusive join is satisfied IMO.
I havn’t been in the code of the inclusive joining gateway and could not show the details.
But the image in my head is, that the process engine has to maintain the state of splitting and joining inclusive gateways. And joining inclusive gateways for me makes only sense after a splitting gateway. Internally the engine only counts tokens and checks if the number of incoming tokens is equal to the overall number of tokens. If this state is reached (all splitted tokens arrived at the joining gateway) the process will continue with the outgoing sequence flow.
If the token is consumed in the “not joined again” end event, the engine is not clever enough to check that the token was expected in the joining inclusive gateway and that the outgoing sequence flow could possibly continue.
It may work in theory (btw. Its hard for me to follow the formal description from the spec) but it won’t work practically in the Camunda engine.
Hope this helps, Ingo
Check out the Limitation box at https://docs.camunda.org/manual/7.12/reference/bpmn20/gateways/inclusive-gateway/ for how the Camunda implementation differs from the spec.
Thank you @thorbenfor the hint! The text in the box states:
it received a number of tokens smaller than the number of incoming sequence flows and there are no more tokens that can arrive at the gateway
Could you explain how the engine determines that “there are no more tokens that can arrive at the gateway”? Does the process model get analyzed? If there is a token that could arrive at the join because there is a path from it to the join, then the join continues to wait, right?
Correct. When a token arrives at the join, the engine traverses the BPMN model starting at the incoming sequence flows and checks if there is a token (or execution in engine terms) that could still reach the join.
That’s also why the join is not triggered when a token takes a “wrong turn” from which it can no longer reach the join: This check is only done when a token arrives at the join.
But then the example by @Ingo_Richtsmeier should work fine. One token is at the join; for the other one it’s unclear in the beginning whether it will arrive there. Later, when the other token “takes the wrong turn”, it becomes clear that no other token will arrive at the join. So it could be activated. The question is: how does the engine decide that two tokens have to arrive for the join to be activated?
I don’t think that’s correct, depending on the order of execution. Here’s how I see it:
- A token reaches the inclusive split, creating two tokens a and b
- Token a moves to Task 1
- Token b moves to Task 2
a reaches the inclusive join and the join conditions are evaluated. The join does not trigger, because b could still reach the join.
b reaches the exclusive gateway, takes the wrong turn and reaches Task 3 from where it can no longer reach the inclusive join.
Token a is now stuck, because in step 5 the process engine does not re-evaluate the inclusive join. If steps 4 and 5 were reversed, then the join would trigger.
Does that make sense?
Aha, now this makes sense. As in “now I understand how the engine works”. But this only reassures me that the inclusive join should be avoided because its behaviour is quite unpredictable. In our example, the process will be stuck if task1 is executed first. But if the task3 is executed first, and only then the task1 (this is possible with asynchronous execution), the join will pass just fine. Hence the result is dependent on the exact state of the process at the moment the first token reaches the join. Which might be very unpredictable (both the question which token arrives first and where the other tokens are at this moment).
Just to make reading this thread easier: this is the process model we use as the example.