From 92df09d1471f10f14f87a91945c07d42e2ca9733 Mon Sep 17 00:00:00 2001 From: uucoding <1311695042@qq.com> Date: Thu, 22 Jan 2026 22:56:57 +0800 Subject: [PATCH 1/2] Fix boundary event iterator desynchronization in ContinueProcessOperation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **The `executeBoundaryEvents` method had a critical iterator desynchronization bug. The `while` loop assumed that the `boundaryEvents` and `boundaryEventExecutions` lists contained matching elements in the same order, but they did not due to inconsistent filtering.** **For example:** - `createBoundaryEvents` returns only: `[TimerExec, ErrorExec]` (compensation events are skipped) - `executeBoundaryEvents` receives: `[Timer, Compensation, Error]` (all events) **Loop pairing comparison:** ``` Expected pairing: Actual incorrect pairing: Timer ↔ TimerExec ✓ Timer ↔ TimerExec ✓ Error ↔ ErrorExec ✓ Compensation ↔ ErrorExec ✗ ``` --- .../impl/agenda/ContinueProcessOperation.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/agenda/ContinueProcessOperation.java b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/agenda/ContinueProcessOperation.java index 3be9e830b77..52473bfd92e 100644 --- a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/agenda/ContinueProcessOperation.java +++ b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/agenda/ContinueProcessOperation.java @@ -15,6 +15,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.stream.Collectors; import org.flowable.bpmn.model.Activity; import org.flowable.bpmn.model.BoundaryEvent; @@ -360,11 +361,8 @@ protected List createBoundaryEvents(List boundar // The parent execution becomes a scope, and a child execution is created for each of the boundary events for (BoundaryEvent boundaryEvent : boundaryEvents) { - if (!(boundaryEvent.getBehavior() instanceof BoundaryEventRegistryEventActivityBehavior)) { - if (CollectionUtil.isEmpty(boundaryEvent.getEventDefinitions()) - || (boundaryEvent.getEventDefinitions().get(0) instanceof CompensateEventDefinition)) { - continue; - } + if (!isExecutableBoundaryEvent(boundaryEvent)) { + continue; } // A Child execution of the current execution is created to represent the boundary event being active @@ -389,6 +387,7 @@ protected List createBoundaryEvents(List boundar protected void executeBoundaryEvents(List boundaryEvents, List boundaryEventExecutions) { if (!CollectionUtil.isEmpty(boundaryEventExecutions)) { + boundaryEvents = boundaryEvents.stream().filter(this::isExecutableBoundaryEvent).collect(Collectors.toList()); Iterator boundaryEventsIterator = boundaryEvents.iterator(); Iterator boundaryEventExecutionsIterator = boundaryEventExecutions.iterator(); @@ -401,4 +400,14 @@ protected void executeBoundaryEvents(List boundaryEvents, List Date: Tue, 3 Feb 2026 20:12:43 +0800 Subject: [PATCH 2/2] Fix boundary event iterator desynchronization in ContinueProcessOperation add test cases --- .../event/compensate/CompensateEventTest.java | 7 +++++ ...tCompensationTimerEventBoundary.bpmn20.xml | 31 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 modules/flowable-engine/src/test/resources/org/flowable/engine/test/bpmn/event/compensate/CompensateEventTest.testCompensationTimerEventBoundary.bpmn20.xml diff --git a/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/event/compensate/CompensateEventTest.java b/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/event/compensate/CompensateEventTest.java index b5eed3897d5..5b85a8c9e23 100644 --- a/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/event/compensate/CompensateEventTest.java +++ b/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/event/compensate/CompensateEventTest.java @@ -337,4 +337,11 @@ public void testCompensateNestedSubprocess() { } + @Test + @Deployment(resources = { "org/flowable/engine/test/bpmn/event/compensate/CompensateEventTest.testCompensationTimerEventBoundary.bpmn20.xml" }) + public void testCompensationTimerEventBoundary() { + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("compensationTimerEventBoundary"); + assertThat(processInstance).isNotNull(); + } + } diff --git a/modules/flowable-engine/src/test/resources/org/flowable/engine/test/bpmn/event/compensate/CompensateEventTest.testCompensationTimerEventBoundary.bpmn20.xml b/modules/flowable-engine/src/test/resources/org/flowable/engine/test/bpmn/event/compensate/CompensateEventTest.testCompensationTimerEventBoundary.bpmn20.xml new file mode 100644 index 00000000000..f831f6d7037 --- /dev/null +++ b/modules/flowable-engine/src/test/resources/org/flowable/engine/test/bpmn/event/compensate/CompensateEventTest.testCompensationTimerEventBoundary.bpmn20.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + PT5M + + + + + + + + + + \ No newline at end of file