cancel
Showing results for 
Search instead for 
Did you mean: 

Start SubProcess using a Signal?

dognose
Champ in-the-making
Champ in-the-making
Hello,

my Process should contain some subprocesses that can be started at any time under given conditions.
The Task that is "triggering" the Sub-Process needs to remain active. (Therefore i can not use a normal flow to the
subprocess, because this flow is only executed if the task is completed)

So i tried to achieve this, using signals, where I send a signal like this:


runtimeService.signalEventReceived("invokeSubProcessC");

I defined ImmediateSignalCatchingEvents for the Subprocesses like this:

CatchEvent -> [ Subtask ]


<intermediateCatchEvent id="catch_invokeSubProcessC" name="SignalCatchEvent">
  <signalEventDefinition signalRef="invokeSubProcessC"></signalEventDefinition>
</intermediateCatchEvent>

<sequenceFlow id="flow9" name="" sourceRef="catch_invokeSubProcessC" targetRef="subProcessC"></sequenceFlow>

<subProcess id="subProcessC" name="Sub Process">

</subProcess>

However, the subprocess is not created, i.e. no instance for the task following the subprocess' start event is created.

What am I doing wrong?

—-

The Activiti Eclipse Designer lacks of "Message" Objects - are they supported by activiti?
(I assume using messages instead of signals would be what i'm looking for)

Currently i'm using a workaround and "forking" the outflow of taskA, so that the subprocess is started and a "new" taskA is created.
However he changes his ID and therefore may not work as expected in a multi-user environment.

Got it:
Signal needs an incoming flow to entering the "waiting" State (so i added a Gateway right afer the Main-Process-Start-Event to send all Subprocesses in the "Waiting-for-signal"-State.
7 REPLIES 7

frederikherema1
Star Contributor
Star Contributor
Can't you add a non-interupting signal-boundary event on your task, and have this flow to a call-activity or subprocess? because of the "cancelActivity" being true, the task WILL NOT end…


<boundaryEvent id="boundary" attachedToRef="task" cancelActivity="false">      
          <signalEventDefinition signalRef="invokeSubProcessC"/>
</boundaryEvent>

dognose
Champ in-the-making
Champ in-the-making
Maybe i'm a bit confused about the BoundarySignalEvents.

I Always thought the "Other Way round" and assumed, that a SignalBoundaryEvent is NOT The trigger, but the handler,
so you can "stop" (or update) a task, if conditions change. So a signal is triggered somewhere in the process and the BoundaryEvent
will catch that Signal even when the associated Task is already running.

(Because it also has the same look like a ImmediateSignalCatching event and looks different than a Throwing Event.)

To go with a Example from the Docu:

[img]http://www.activiti.org/userguide/images/bpmn.boundary.signal.event.png[/img]

Here i Assume that the task will be active until the "Alert" Signal is triggered from Somewhere else - right?

And thats basically …

I start to understand: You mean i should simple throw the signal "Alert" inside the "do Something" task in Order to proceed with the flow "on Alert".

Well, i dunno if theres a difference to my current solution, which looks (simplified) like this:

[img]http://www.abload.de/img/capturemrsil.png[/img]

Both cases require the "signal" to be thrown programmatically I assume?

Ofc, even if those mehtods are funcitonaly equal, yours is clearer to understand, because you can see, where the signal's coming from.
(if you dont throw the same signal at other tasks)

jbarrez
Star Contributor
Star Contributor
Yes, as far as I understand you reasoning it is correct. The task will remain active until the signal is thrown.

frederikherema1
Star Contributor
Star Contributor
But if you use the "cancelActivity=false" on the boundary-event, the task WILL NOT be cancelled once the signal is thrown.

Example in our test cases. Consider this process, a task with a signal boundary-event on it:


<?xml version="1.0" encoding="UTF-8"?>
<definitions id="definitions" xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
  xmlns:activiti="http://activiti.org/bpmn" targetNamespace="Examples">

  <signal id="alertSignal" name="alert" />

  <process id="nonInterruptingSignalEvent">

    <startEvent id="theStart" />

    <sequenceFlow id="flow1" sourceRef="theStart" targetRef="theUserTask" />

    <userTask id="theUserTask" name="My User Task" />

    <boundaryEvent id="signal" attachedToRef="theUserTask" cancelActivity="false">
      <signalEventDefinition signalRef="alertSignal" />
    </boundaryEvent>
   
    <sequenceFlow id="flow2" sourceRef="theUserTask" targetRef="theEnd" />
   
    <endEvent id="theEnd" />
   
    <sequenceFlow id="flow3" sourceRef="signal" targetRef="theUserTask2" />
   
    <userTask id="theUserTask2" name="My Second User Task" />
   
    <sequenceFlow id="flow4" sourceRef="theUserTask2" targetRef="theEnd2" />
   
    <endEvent id="theEnd2" />
  </process>

</definitions>

And, after signaling the process, the task is still present and signal flow is taken as well:


@Deployment
  public void testNonInterruptingSignal() {
    ProcessInstance pi = runtimeService.startProcessInstanceByKey("nonInterruptingSignalEvent");
   
    List<Task> tasks = taskService.createTaskQuery().processInstanceId(pi.getProcessInstanceId()).list();
    assertEquals(1,  tasks.size());
    Task currentTask = tasks.get(0);
    assertEquals("My User Task", currentTask.getName());
   
    runtimeService.signalEventReceived("alert");
   
    tasks = taskService.createTaskQuery().processInstanceId(pi.getProcessInstanceId()).list();
    assertEquals(2,  tasks.size());
   
    for (Task task : tasks) {
      if (!task.getName().equals("My User Task") && !task.getName().equals("My Second User Task")) {
        fail("Expected: <My User Task> or <My Second User Task> but was <" + task.getName() + ">.");
      }
    }



Source: org.activiti.engine.test.bpmn.event.signal.SignalEventTest

dognose
Champ in-the-making
Champ in-the-making
helpfull post

basically that was the Function i assumed. However this way, it won't work.

I get the exception:


[org.activiti.engine.impl.interceptor.CommandContext] (http-localhost-127.0.0.1-8090-11) Error while closing command context: org.activiti.engine.ActivitiException: Execution '1008' has not subscribed to a signal event with name 'startSubProcessAfromX'.
at org.activiti.engine.impl.cmd.SignalEventReceivedCmd.execute(SignalEventReceivedCmd.java:52) [activiti-engine-5.10.jar:5.10]
at org.activiti.engine.impl.cmd.SignalEventReceivedCmd.execute(SignalEventReceivedCmd.java:29) [activiti-engine-5.10.jar:5.10]


currently i designed it like this:

[img]http://download.dog-net.org/easyshare/pictures/20121024110950.jpg[/img]

using 2 Signals startSubProcessAfromY and startSubProcessAfromX

XML:


<definitions …>
  <signal id="startSubProcessAfromX" name="startSubProcessAfromX"></signal>
  <signal id="startSubProcessAfromY" name="startSubProcessAfromY"></signal>
  …
  <process id="processP" name="processP">
    …
    <userTask id="TaskX" …></userTask>
    <boundaryEvent id="boundarysignal1" cancelActivity="false" attachedToRef="TaskX">
      <signalEventDefinition signalRef="startSubProcessAfromX"></signalEventDefinition>
    </boundaryEvent>
    <userTask id="TaskY" …></userTask>
    <boundaryEvent id="boundarysignal2" cancelActivity="false" attachedToRef="TaskY">
      <signalEventDefinition signalRef="startSubProcessAfromY"></signalEventDefinition>
    </boundaryEvent>
    …
    <sequenceFlow id="flow34" name="" sourceRef="boundarysignal1" targetRef="exclusivegateway1"></sequenceFlow>
    <sequenceFlow id="flow35" name="" sourceRef="boundarysignal2" targetRef="exclusivegateway1"></sequenceFlow>
    …

The Task themselves are made of a form, where a button "triggers" the signal:


public void triggerSubProcessAButtonClicked(BusinessProcess businessProcess){
  …
  runtimeService.signalEventReceived("startSubProcessAfromX", businessProcess.getProcessInstanceId());
  … 
}

And exactly at this line, the exception is thrown. (And yes, i'm definitly triggering The Signal "…fromX" inside Task X)

Only difference is that i just send the signal to the current instance, not to all instances.

ps.: If the above code contains typos and/or case-issues - they are not there i just replaced the names for better understanding 🙂

frederikherema1
Star Contributor
Star Contributor
Try signaling the exact execution instead of the process-instance… Try querying the task and use the executionId you get from there.

dognose
Champ in-the-making
Champ in-the-making
Try signaling the exact execution instead of the process-instance… Try querying the task and use the executionId you get from there.

Smiley Surprisedops: Should have tried that – works.


//send signal to current task only.
String taskId = Helper.getContextHelper().getParameter(RequestConstants.TASK_ID_PARAMETER_NAME);
runtimeService.signalEventReceived(TaskConstants.TRIGGER_SUBPROCESS_SIGNAL_NAME, taskId);

Sir ThxAlot checked in at forums.activiti.org :ugeek: