From e459d5040caf150da782b51445531b70fba194da Mon Sep 17 00:00:00 2001 From: martin-grofcik Date: Thu, 26 Mar 2026 17:54:06 +0100 Subject: [PATCH 1/6] ##4194 pass signal to the next subscribed listener --- .../engine/impl/event/SignalEventHandler.java | 7 ++++- .../bpmn/event/signal/SignalEventTest.java | 29 ++++++++++++++++--- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/event/SignalEventHandler.java b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/event/SignalEventHandler.java index 0555264646c..524a5b6d814 100644 --- a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/event/SignalEventHandler.java +++ b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/event/SignalEventHandler.java @@ -24,6 +24,8 @@ import org.flowable.engine.impl.util.ProcessInstanceHelper; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.eventsubscription.service.impl.persistence.entity.EventSubscriptionEntity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @author Daniel Meyer @@ -31,6 +33,8 @@ */ public class SignalEventHandler extends AbstractEventHandler { + private static final Logger LOG = LoggerFactory.getLogger(SignalEventHandler.class); + public static final String EVENT_HANDLER_TYPE = "signal"; @Override @@ -52,7 +56,8 @@ public void handleEvent(EventSubscriptionEntity eventSubscription, Object payloa ProcessDefinition processDefinition = ProcessDefinitionUtil.getProcessDefinition(processDefinitionId); if (processDefinition.isSuspended()) { - throw new FlowableException("Could not handle signal: process definition with id: " + processDefinitionId + " is suspended for " + eventSubscription); + LOG.info("Could not handle signal: process definition with id: {} is suspended for {}", processDefinitionId, eventSubscription); + return; } // Start process instance via the flow element linked to the event diff --git a/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/event/signal/SignalEventTest.java b/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/event/signal/SignalEventTest.java index f00977674c8..e9c88b1b372 100644 --- a/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/event/signal/SignalEventTest.java +++ b/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/event/signal/SignalEventTest.java @@ -537,6 +537,27 @@ public void testSignalUserTask() { .isExactlyInstanceOf(FlowableException.class); } + @Test + public void testDuplicatedSuspendedSignalStartEventFromProcess() { + // Deploy test processes + repositoryService.createDeployment() + .addClasspathResource("org/flowable/engine/test/bpmn/event/signal/SignalEventTest.testSignalStartEvent.bpmn20.xml") + .deploy(); + repositoryService.suspendProcessDefinitionByKey("processWithSignalStart1"); + runtimeService.signalEventReceived("nonExisting"); + // Starting the process that fires the signal should start three process + // instances that are listening on that signal + runtimeService.startProcessInstanceByKey("processWithSignalThrow"); + + // Verify + assertThat(runtimeService.createProcessInstanceQuery().count()).isEqualTo(2); + assertThat(taskService.createTaskQuery().list()).extracting(Task::getName) + .containsExactlyInAnyOrder("Task in process B", "Task in process C"); + + // Cleanup + cleanup(); + } + @Test public void testSignalStartEventFromProcess() { @@ -805,12 +826,12 @@ public void testSignalStartEventWithSuspendedDefinition() { repositoryService.suspendProcessDefinitionByKey("processWithSignalStart1"); - assertThatThrownBy(() -> runtimeService.startProcessInstanceByKey("processWithSignalThrow")) - .as("Suspended process definition should fail") - .isExactlyInstanceOf(FlowableException.class); + runtimeService.startProcessInstanceByKey("processWithSignalThrow"); // Verify - assertThat(runtimeService.createProcessInstanceQuery().count()).isZero(); + assertThat(runtimeService.createProcessInstanceQuery().count()) + .as("Signal throw event is swallowed for suspended process") + .isZero(); repositoryService.activateProcessDefinitionByKey("processWithSignalStart1"); From 154e53f234e4e194fbe51b85717e67453bf65cae Mon Sep 17 00:00:00 2001 From: martin-grofcik Date: Thu, 26 Mar 2026 19:03:44 +0100 Subject: [PATCH 2/6] ##4194 test fix --- .../engine/test/bpmn/event/signal/SignalEventTest.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/event/signal/SignalEventTest.java b/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/event/signal/SignalEventTest.java index e9c88b1b372..81d462678b3 100644 --- a/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/event/signal/SignalEventTest.java +++ b/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/event/signal/SignalEventTest.java @@ -829,9 +829,10 @@ public void testSignalStartEventWithSuspendedDefinition() { runtimeService.startProcessInstanceByKey("processWithSignalThrow"); // Verify - assertThat(runtimeService.createProcessInstanceQuery().count()) + assertThat(runtimeService.createProcessInstanceQuery().list()) .as("Signal throw event is swallowed for suspended process") - .isZero(); + .extracting(ProcessInstance::getProcessDefinitionKey) + .containsExactlyInAnyOrder("processWithSignalStart2","processWithSignalStart3"); repositoryService.activateProcessDefinitionByKey("processWithSignalStart1"); @@ -840,8 +841,8 @@ public void testSignalStartEventWithSuspendedDefinition() { runtimeService.startProcessInstanceByKey("processWithSignalThrow"); // Verify - assertThat(runtimeService.createProcessInstanceQuery().count()).isEqualTo(3); - assertThat(taskService.createTaskQuery().count()).isEqualTo(3); + assertThat(runtimeService.createProcessInstanceQuery().count()).isEqualTo(5); + assertThat(taskService.createTaskQuery().count()).isEqualTo(5); // Cleanup cleanup(); From 5f5856ad0bc94d03efab93f20e755794bd5c4658 Mon Sep 17 00:00:00 2001 From: martin-grofcik Date: Thu, 26 Mar 2026 19:08:42 +0100 Subject: [PATCH 3/6] ##4194 test clarification --- .../engine/test/bpmn/event/signal/SignalEventTest.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/event/signal/SignalEventTest.java b/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/event/signal/SignalEventTest.java index 81d462678b3..aa41c555c04 100644 --- a/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/event/signal/SignalEventTest.java +++ b/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/event/signal/SignalEventTest.java @@ -544,9 +544,12 @@ public void testDuplicatedSuspendedSignalStartEventFromProcess() { .addClasspathResource("org/flowable/engine/test/bpmn/event/signal/SignalEventTest.testSignalStartEvent.bpmn20.xml") .deploy(); repositoryService.suspendProcessDefinitionByKey("processWithSignalStart1"); + + // An example of behavior when there is no subscription to the signal. runtimeService.signalEventReceived("nonExisting"); - // Starting the process that fires the signal should start three process - // instances that are listening on that signal + + // Starting the process that fires the signal should start 2 process + // instances that are listening on that signal. The suspended one is not included. runtimeService.startProcessInstanceByKey("processWithSignalThrow"); // Verify From eb1e8729499aed224b9a70067dfd0ccfb77b67b9 Mon Sep 17 00:00:00 2001 From: martin-grofcik Date: Sat, 28 Mar 2026 10:07:40 +0100 Subject: [PATCH 4/6] #4194 do not return suspended definitions for signal subscription --- .../engine/impl/event/SignalEventHandler.java | 8 -------- .../test/bpmn/event/signal/SignalEventTest.java | 15 +++++++-------- .../db/mapping/entity/EventSubscription.xml | 8 +++++++- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/event/SignalEventHandler.java b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/event/SignalEventHandler.java index 524a5b6d814..fb73068a33b 100644 --- a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/event/SignalEventHandler.java +++ b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/event/SignalEventHandler.java @@ -32,9 +32,6 @@ * @author Joram Barrez */ public class SignalEventHandler extends AbstractEventHandler { - - private static final Logger LOG = LoggerFactory.getLogger(SignalEventHandler.class); - public static final String EVENT_HANDLER_TYPE = "signal"; @Override @@ -55,11 +52,6 @@ public void handleEvent(EventSubscriptionEntity eventSubscription, Object payloa org.flowable.bpmn.model.Process process = ProcessDefinitionUtil.getProcess(processDefinitionId); ProcessDefinition processDefinition = ProcessDefinitionUtil.getProcessDefinition(processDefinitionId); - if (processDefinition.isSuspended()) { - LOG.info("Could not handle signal: process definition with id: {} is suspended for {}", processDefinitionId, eventSubscription); - return; - } - // Start process instance via the flow element linked to the event FlowElement flowElement = process.getFlowElement(eventSubscription.getActivityId(), true); if (flowElement == null) { diff --git a/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/event/signal/SignalEventTest.java b/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/event/signal/SignalEventTest.java index aa41c555c04..66cba2bcc31 100644 --- a/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/event/signal/SignalEventTest.java +++ b/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/event/signal/SignalEventTest.java @@ -538,11 +538,8 @@ public void testSignalUserTask() { } @Test + @Deployment(resources={"org/flowable/engine/test/bpmn/event/signal/SignalEventTest.testSignalStartEvent.bpmn20.xml"}) public void testDuplicatedSuspendedSignalStartEventFromProcess() { - // Deploy test processes - repositoryService.createDeployment() - .addClasspathResource("org/flowable/engine/test/bpmn/event/signal/SignalEventTest.testSignalStartEvent.bpmn20.xml") - .deploy(); repositoryService.suspendProcessDefinitionByKey("processWithSignalStart1"); // An example of behavior when there is no subscription to the signal. @@ -557,8 +554,6 @@ public void testDuplicatedSuspendedSignalStartEventFromProcess() { assertThat(taskService.createTaskQuery().list()).extracting(Task::getName) .containsExactlyInAnyOrder("Task in process B", "Task in process C"); - // Cleanup - cleanup(); } @Test @@ -766,8 +761,12 @@ public void testSignalCatchSuspendedDefinition() { runtimeService.startProcessInstanceByKey("throwSignal"); - assertThat(createEventSubscriptionQuery().count()).isZero(); - assertThat(runtimeService.createProcessInstanceQuery().count()).isZero(); + assertThat(createEventSubscriptionQuery().count()) + .as("Process definition is suspended and subscription is kept untouched despite of received signal.") + .isEqualTo(1); + assertThat(runtimeService.createProcessInstanceQuery().count()) + .as("Process definition is suspended and process instance is kept untouched despite of received signal.") + .isEqualTo(1); } @Test diff --git a/modules/flowable-eventsubscription-service/src/main/resources/org/flowable/eventsubscription/service/db/mapping/entity/EventSubscription.xml b/modules/flowable-eventsubscription-service/src/main/resources/org/flowable/eventsubscription/service/db/mapping/entity/EventSubscription.xml index dec505c84ba..484ca3f656d 100644 --- a/modules/flowable-eventsubscription-service/src/main/resources/org/flowable/eventsubscription/service/db/mapping/entity/EventSubscription.xml +++ b/modules/flowable-eventsubscription-service/src/main/resources/org/flowable/eventsubscription/service/db/mapping/entity/EventSubscription.xml @@ -240,12 +240,18 @@ select * from ${prefix}ACT_RU_EVENT_SUBSCR EVT left outer join ${prefix}ACT_RU_EXECUTION EXC on EVT.EXECUTION_ID_ = EXC.ID_ + left outer join ${prefix}ACT_RE_PROCDEF DEF on EVT.PROC_DEF_ID_ = DEF.ID_ where EVENT_TYPE_ = 'signal' and EVENT_NAME_ = #{parameter.eventName, jdbcType=NVARCHAR} and ( (EVT.EXECUTION_ID_ is null) or - (EVT.EXECUTION_ID_ is not null AND EXC.SUSPENSION_STATE_ = 1) + (EVT.EXECUTION_ID_ is not null AND EXC.SUSPENSION_STATE_ = 1) + ) + and ( + (EVT.PROC_DEF_ID_ is null) + or + (EVT.PROC_DEF_ID_ is not null AND DEF.SUSPENSION_STATE_ = 1) ) and EVT.TENANT_ID_ = #{parameter.tenantId, jdbcType=NVARCHAR} From 82bd8d3175ccc8fdca836047f738e775dd88f882 Mon Sep 17 00:00:00 2001 From: martin-grofcik Date: Tue, 7 Apr 2026 08:38:32 +0200 Subject: [PATCH 5/6] #4194 allow to continue in execution for which definition is suspended. --- .../test/bpmn/event/signal/SignalEventTest.java | 8 ++------ .../service/db/mapping/entity/EventSubscription.xml | 12 +++--------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/event/signal/SignalEventTest.java b/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/event/signal/SignalEventTest.java index 66cba2bcc31..d0da2fdcffd 100644 --- a/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/event/signal/SignalEventTest.java +++ b/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/event/signal/SignalEventTest.java @@ -761,12 +761,8 @@ public void testSignalCatchSuspendedDefinition() { runtimeService.startProcessInstanceByKey("throwSignal"); - assertThat(createEventSubscriptionQuery().count()) - .as("Process definition is suspended and subscription is kept untouched despite of received signal.") - .isEqualTo(1); - assertThat(runtimeService.createProcessInstanceQuery().count()) - .as("Process definition is suspended and process instance is kept untouched despite of received signal.") - .isEqualTo(1); + assertThat(createEventSubscriptionQuery().count()).isZero(); + assertThat(runtimeService.createProcessInstanceQuery().count()).isZero(); } @Test diff --git a/modules/flowable-eventsubscription-service/src/main/resources/org/flowable/eventsubscription/service/db/mapping/entity/EventSubscription.xml b/modules/flowable-eventsubscription-service/src/main/resources/org/flowable/eventsubscription/service/db/mapping/entity/EventSubscription.xml index 484ca3f656d..27ac22ee5f3 100644 --- a/modules/flowable-eventsubscription-service/src/main/resources/org/flowable/eventsubscription/service/db/mapping/entity/EventSubscription.xml +++ b/modules/flowable-eventsubscription-service/src/main/resources/org/flowable/eventsubscription/service/db/mapping/entity/EventSubscription.xml @@ -240,18 +240,12 @@ select * from ${prefix}ACT_RU_EVENT_SUBSCR EVT left outer join ${prefix}ACT_RU_EXECUTION EXC on EVT.EXECUTION_ID_ = EXC.ID_ - left outer join ${prefix}ACT_RE_PROCDEF DEF on EVT.PROC_DEF_ID_ = DEF.ID_ where EVENT_TYPE_ = 'signal' and EVENT_NAME_ = #{parameter.eventName, jdbcType=NVARCHAR} and ( - (EVT.EXECUTION_ID_ is null) - or - (EVT.EXECUTION_ID_ is not null AND EXC.SUSPENSION_STATE_ = 1) - ) - and ( - (EVT.PROC_DEF_ID_ is null) - or - (EVT.PROC_DEF_ID_ is not null AND DEF.SUSPENSION_STATE_ = 1) + (EVT.EXECUTION_ID_ is null and EVT.PROC_DEF_ID_ is not null and exists (select 1 from ACT_RE_PROCDEF DEF where DEF.ID_ = EVT.PROC_DEF_ID_ and DEF.SUSPENSION_STATE_ = 1)) + or + (EVT.EXECUTION_ID_ is not null AND EXC.SUSPENSION_STATE_ = 1) ) and EVT.TENANT_ID_ = #{parameter.tenantId, jdbcType=NVARCHAR} From a9e14b909bf76ecfa3014b558a96ec77a78ee100 Mon Sep 17 00:00:00 2001 From: martin-grofcik Date: Tue, 7 Apr 2026 20:24:45 +0200 Subject: [PATCH 6/6] #4194 return non process subscribers --- .../flowable/cmmn/test/SignalEventTest.java | 86 ++++++++++++------- .../db/mapping/entity/EventSubscription.xml | 2 + 2 files changed, 59 insertions(+), 29 deletions(-) diff --git a/modules/flowable-cmmn-engine-configurator/src/test/java/org/flowable/cmmn/test/SignalEventTest.java b/modules/flowable-cmmn-engine-configurator/src/test/java/org/flowable/cmmn/test/SignalEventTest.java index b87785ecf56..983799a439c 100644 --- a/modules/flowable-cmmn-engine-configurator/src/test/java/org/flowable/cmmn/test/SignalEventTest.java +++ b/modules/flowable-cmmn-engine-configurator/src/test/java/org/flowable/cmmn/test/SignalEventTest.java @@ -44,16 +44,13 @@ public void testSignal() { assertThat(cmmnTaskService.createTaskQuery().caseInstanceId(caseInstance.getId()).count()).isZero(); Task task = processEngineTaskService.createTaskQuery().caseInstanceIdWithChildren(caseInstance.getId()).singleResult(); - assertThat(task).isNotNull(); - assertThat(task.getTaskDefinitionKey()).isEqualTo("theTask"); - assertThat(task.getName()).isEqualTo("my task"); + assertThatCaseTaskWasCreated(task); - EventSubscription eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance.getId()).singleResult(); - assertThat(eventSubscription.getEventName()).isEqualTo("testSignal"); + assertThatEventSubscriptionExists(caseInstance); processEngineTaskService.complete(task.getId()); - eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance.getId()).singleResult(); + EventSubscription eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance.getId()).singleResult(); assertThat(eventSubscription).isNull(); Task task2 = processEngineTaskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).singleResult(); @@ -94,22 +91,18 @@ public void testMultipleSignals() { assertThat(cmmnTaskService.createTaskQuery().caseInstanceId(caseInstance.getId()).count()).isZero(); Task task = processEngineTaskService.createTaskQuery().caseInstanceIdWithChildren(caseInstance.getId()).singleResult(); - assertThat(task).isNotNull(); - assertThat(task.getTaskDefinitionKey()).isEqualTo("theTask"); - assertThat(task.getName()).isEqualTo("my task"); + assertThatCaseTaskWasCreated(task); - EventSubscription eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance.getId()).singleResult(); - assertThat(eventSubscription.getEventName()).isEqualTo("testSignal"); + assertThatEventSubscriptionExists(caseInstance); - EventSubscription anotherEventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(anotherCaseInstance.getId()).singleResult(); - assertThat(anotherEventSubscription.getEventName()).isEqualTo("testSignal"); + assertThatEventSubscriptionExists(anotherCaseInstance); processEngineTaskService.complete(task.getId()); - eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance.getId()).singleResult(); + EventSubscription eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance.getId()).singleResult(); assertThat(eventSubscription).isNull(); - anotherEventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(anotherCaseInstance.getId()).singleResult(); + EventSubscription anotherEventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(anotherCaseInstance.getId()).singleResult(); assertThat(anotherEventSubscription).isNull(); Task task2 = processEngineTaskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).singleResult(); @@ -152,16 +145,13 @@ public void testSignalWithInstanceScope() { assertThat(cmmnTaskService.createTaskQuery().caseInstanceId(caseInstance.getId()).count()).isZero(); Task task = processEngineTaskService.createTaskQuery().caseInstanceIdWithChildren(caseInstance.getId()).singleResult(); - assertThat(task).isNotNull(); - assertThat(task.getTaskDefinitionKey()).isEqualTo("theTask"); - assertThat(task.getName()).isEqualTo("my task"); + assertThatCaseTaskWasCreated(task); - EventSubscription eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance.getId()).singleResult(); - assertThat(eventSubscription.getEventName()).isEqualTo("testSignal"); + assertThatEventSubscriptionExists(caseInstance); processEngineTaskService.complete(task.getId()); - eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance.getId()).singleResult(); + EventSubscription eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance.getId()).singleResult(); assertThat(eventSubscription).isNull(); Task task2 = processEngineTaskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).singleResult(); @@ -201,19 +191,17 @@ public void testMultipleSignalWithInstanceScope() { assertThat(cmmnTaskService.createTaskQuery().caseInstanceId(caseInstance.getId()).count()).isZero(); - EventSubscription eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance.getId()).singleResult(); - assertThat(eventSubscription.getEventName()).isEqualTo("testSignal"); + assertThatEventSubscriptionExists(caseInstance); - EventSubscription anotherEventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(anotherCaseInstance.getId()).singleResult(); - assertThat(anotherEventSubscription.getEventName()).isEqualTo("testSignal"); + assertThatEventSubscriptionExists(anotherCaseInstance); Task task = processEngineTaskService.createTaskQuery().caseInstanceIdWithChildren(caseInstance.getId()).singleResult(); processEngineTaskService.complete(task.getId()); - eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance.getId()).singleResult(); + EventSubscription eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance.getId()).singleResult(); assertThat(eventSubscription).isNull(); - anotherEventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(anotherCaseInstance.getId()).singleResult(); + EventSubscription anotherEventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(anotherCaseInstance.getId()).singleResult(); assertThat(anotherEventSubscription.getEventName()).isEqualTo("testSignal"); Task task2 = processEngineTaskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).singleResult(); @@ -259,8 +247,7 @@ public void testTerminateCaseInstanceWithSignal() { assertThat(cmmnTaskService.createTaskQuery().caseInstanceId(caseInstance.getId()).count()).isZero(); - EventSubscription eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance.getId()).singleResult(); - assertThat(eventSubscription.getEventName()).isEqualTo("testSignal"); + assertThatEventSubscriptionExists(caseInstance); cmmnRuntimeService.terminateCaseInstance(caseInstance.getId()); @@ -301,4 +288,45 @@ public void testPassVariablesThroughCaseInstanceService() { } + @Test + @CmmnDeployment(resources = { "org/flowable/cmmn/test/processTaskWithSignalListener.cmmn" }) + public void multipleSignalSubscribers() { + Deployment deployment = this.processEngineRepositoryService.createDeployment(). + addClasspathResource("org/flowable/cmmn/test/signalProcess.bpmn20.xml"). + deploy(); + + try { + CaseInstance caseInstance1 = cmmnRuntimeService.createCaseInstanceBuilder().caseDefinitionKey("signalCase").start(); + CaseInstance caseInstance2 = cmmnRuntimeService.createCaseInstanceBuilder().caseDefinitionKey("signalCase").start(); + + assertThat(cmmnTaskService.createTaskQuery().caseInstanceId(caseInstance1.getId()).count()).isZero(); + assertThat(cmmnRuntimeService.createEventSubscriptionQuery().count()).isEqualTo(2L); + + Task task = processEngineTaskService.createTaskQuery().caseInstanceIdWithChildren(caseInstance1.getId()).singleResult(); + + assertThatCaseTaskWasCreated(task); + assertThatEventSubscriptionExists(caseInstance1); + assertThatEventSubscriptionExists(caseInstance2); + + processEngineTaskService.complete(task.getId()); + + assertThat(cmmnRuntimeService.createEventSubscriptionQuery().count()) + .as("The signal triggers 2 subscribers.") + .isZero(); + } finally { + processEngine.getRepositoryService().deleteDeployment(deployment.getId(), true); + } + } + + private void assertThatEventSubscriptionExists(CaseInstance caseInstance1) { + EventSubscription eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance1.getId()).singleResult(); + assertThat(eventSubscription.getEventName()).isEqualTo("testSignal"); + } + + private static void assertThatCaseTaskWasCreated(Task task) { + assertThat(task).isNotNull(); + assertThat(task.getTaskDefinitionKey()).isEqualTo("theTask"); + assertThat(task.getName()).isEqualTo("my task"); + } + } diff --git a/modules/flowable-eventsubscription-service/src/main/resources/org/flowable/eventsubscription/service/db/mapping/entity/EventSubscription.xml b/modules/flowable-eventsubscription-service/src/main/resources/org/flowable/eventsubscription/service/db/mapping/entity/EventSubscription.xml index 27ac22ee5f3..cfddaa16945 100644 --- a/modules/flowable-eventsubscription-service/src/main/resources/org/flowable/eventsubscription/service/db/mapping/entity/EventSubscription.xml +++ b/modules/flowable-eventsubscription-service/src/main/resources/org/flowable/eventsubscription/service/db/mapping/entity/EventSubscription.xml @@ -246,6 +246,8 @@ (EVT.EXECUTION_ID_ is null and EVT.PROC_DEF_ID_ is not null and exists (select 1 from ACT_RE_PROCDEF DEF where DEF.ID_ = EVT.PROC_DEF_ID_ and DEF.SUSPENSION_STATE_ = 1)) or (EVT.EXECUTION_ID_ is not null AND EXC.SUSPENSION_STATE_ = 1) + or + (EVT.SCOPE_TYPE_ is not null and EVT.SCOPE_ID_ is not null and EVT.SCOPE_DEFINITION_ID_ is not null and EVT.SUB_SCOPE_ID_ is not null) ) and EVT.TENANT_ID_ = #{parameter.tenantId, jdbcType=NVARCHAR}