-
Notifications
You must be signed in to change notification settings - Fork 556
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reject duplicate parallel gateway activate command #9759
Reject duplicate parallel gateway activate command #9759
Conversation
Parallel gateways get activated by taking a sequence flow and checking if the number of taken flows is greater or equal to the number of incoming sequence flows. If this is the case an activate command is sent. The number of taken sequence flows get rest upon activation of the parallel gateway. This proves troublesome when a "bad" model causes one of the incoming sequence flows to be taken twice. This could result in the activation command being sent twice. Imagine there is a parallel gateway with 2 incoming flows. What would happen is: 1. First flow is taken 2. Second flow is taken. Incoming flows == taken flows so an activate command is sent. 3. Second flow is taken again. The first activate command has not been processed yet. The number of taken flows has not been reset. As a result incoming flows < taken flows. A second activate command is sent.
@korthout I have removed you as a reviewer for now, since the solution is flawed. Sorry! |
...c/main/java/io/camunda/zeebe/engine/processing/bpmn/ProcessInstanceStateTransitionGuard.java
Outdated
Show resolved
Hide resolved
@remcowesterhoud I like the idea of rejecting the activate command for the parallel gateway when it isn't yet ready to activate. It would allow us to remove the logic that determines whether or not to write the activate command, and entirely move it to the processor. This also makes it more in line with other concurrent behaviors (e.g. an element might be planned to be completed because a COMPLETE_ELEMENT was written for it on the log, but before it is processed a TERMINATE_ELEMENT is processed due to some interruption like a boundary event, we then reject the COMPLETE_ELEMENT command when we try to process it later). To make this idea work for Start Process Instance Anywhere, we need something special. We'll need to increment the number of taken sequence flows before processing the ACTIVATE_ELEMENT of the parallel gateway:
We could do that by introducing a new event applier for ProcessInstanceCreation CREATED events, which is written (and applied) before the ACTIVATE_ELEMENT of the parallel gateway is processed. The hard part is to find the related flow scope instance, because you don't have access to the key of the parallel gateway's element instance (i.e. the parallel gateway isn't created yet). There is no direct access to this, but you could traverse the process instance's process model using @remcowesterhoud If you want we can talk about it in person. |
…cess anywhere In the scenario where we start a process instance at a Parallel Gateway we will have to increment the number of taken sequence flows manually. If we don't do this the new state transition guard will find no taken sequence flows, where it has N amount of incoming flows. Resulting in a command rejection. By incrementing the number of taken sequence flows for each incoming flow of the parallel gateway we can circumvent this rejection and activate the gateway as expected.
This check has been moved to the ProcessInstanceStateTransitionGuard. We can always send the activate command. If a parallel gateway cannot be activated the command gets rejected. This might have a small impact on performance, as now we are sending commands and rejecting them, as opposed to not sending the commands at all.
@korthout Thanks for your help ❤️ I have resolved the issues, please have a look! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚀 Nice work @remcowesterhoud
🔧 Please make it clear in the PR description what this PR changes.
🔧 Please document the new Parallel Gateway behavior.
💭 This will probably not backport so easily to the older versions, because of the new event applier (those versions don't know about start instructions).
👍 LGTM
...main/java/io/camunda/zeebe/engine/processing/deployment/model/element/ExecutableProcess.java
Show resolved
Hide resolved
.../main/java/io/camunda/zeebe/engine/state/appliers/ProcessInstanceCreationCreatedApplier.java
Outdated
Show resolved
Hide resolved
.../main/java/io/camunda/zeebe/engine/state/appliers/ProcessInstanceCreationCreatedApplier.java
Show resolved
Hide resolved
.../main/java/io/camunda/zeebe/engine/state/appliers/ProcessInstanceCreationCreatedApplier.java
Show resolved
Hide resolved
.../main/java/io/camunda/zeebe/engine/state/appliers/ProcessInstanceCreationCreatedApplier.java
Show resolved
Hide resolved
.../main/java/io/camunda/zeebe/engine/processing/bpmn/behavior/BpmnStateTransitionBehavior.java
Show resolved
Hide resolved
engine/src/test/java/io/camunda/zeebe/engine/processing/bpmn/gateway/ParallelGatewayTest.java
Outdated
Show resolved
Hide resolved
bors merge |
9759: Reject duplicate parallel gateway activate command r=remcowesterhoud a=remcowesterhoud ## Description <!-- Please explain the changes you made here. --> Parallel gateways get activated by taking a sequence flow and checking if the number of taken flows is greater or equal to the number of incoming sequence flows. If this is the case an activate command is sent. The number of taken sequence flows get rest upon activation of the parallel gateway. This proves troublesome when a "bad" model causes one of the incoming sequence flows to be taken twice. This could result in the activation command being sent twice. Imagine there is a parallel gateway with 2 incoming flows. What would happen is: 1. First flow is taken 2. Second flow is taken. Incoming flows == taken flows so an activate command is sent. 3. Second flow is taken again. The first activate command has not been processed yet. The number of taken flows has not been reset. As a result incoming flows < taken flows. A second activate command is sent. This is solved by always sending an activate command when a sequence flow is taken. Once the `BpmnStreamProcessor` tries to process the record it will check if the state is valid. Here a check has been added to verify that when we receive an activate command for a parallel gateway we will first check if all the incoming flows have been taken. If this is not the case we will reject the command. ## Related issues <!-- Which issues are closed by this PR or are related --> closes #6778 Co-authored-by: Remco Westerhoud <remco@westerhoud.nl>
Build failed: |
Expand the test to also assert that we reject the command twice, and only activate it once.
327fd61
to
aa9fab1
Compare
bors retry |
Build succeeded: |
Successfully created backport PR #9822 for |
Successfully created backport PR #9823 for |
9825: Joining parallel gateway doc r=remcowesterhoud a=remcowesterhoud ## Description <!-- Please explain the changes you made here. --> Add a bpmn diagram explaining the activation of a joining parallel gateway ## Related issues <!-- Which issues are closed by this PR or are related --> relates to #9759 Co-authored-by: Remco Westerhoud <remco@westerhoud.nl>
@remcowesterhoud Please add this to the release notes |
Description
Parallel gateways get activated by taking a sequence flow and checking if the number of taken flows is greater or equal to the number of incoming sequence flows. If this is the case an activate command is sent. The number of taken sequence flows get rest upon activation of the parallel gateway.
This proves troublesome when a "bad" model causes one of the incoming sequence flows to be taken twice. This could result in the activation command being sent twice. Imagine there is a parallel gateway with 2 incoming flows. What would happen is:
This is solved by always sending an activate command when a sequence flow is taken. Once the
BpmnStreamProcessor
tries to process the record it will check if the state is valid. Here a check has been added to verify that when we receive an activate command for a parallel gateway we will first check if all the incoming flows have been taken. If this is not the case we will reject the command.Related issues
closes #6778
Definition of Done
Not all items need to be done depending on the issue and the pull request.
Code changes:
backport stable/1.3
) to the PR, in case that fails you need to create backports manually.Testing:
Documentation:
Please refer to our review guidelines.