Hook when UserTask is ended by boundary event

I have some independent camunda engines that propagate their userTasks to a central taskList (via TaskCreateListener). This creates “proxyTasks” that, when completed, also complete the “remoteTask”.

I am able to recognise if the remoteTask is completed directly (OnTaskComplete) or the process instance is cancelled (OnTaskDelete), in these cases I notify the central tasklist that the proxyTask is no longer needed.

But what if the remoteTask is ended by a boundaryEvent (Timer, Message, …)? Neither the complete nor the delete listeners are called. How can I avoid leaving the proxyTask open in this case? Anything in the engine/spec? Or would this require a 5th taskListener-event “onInterrupt”?

Hi Jan,

The delete event should cover this case as well and we also have a test for this case (see https://github.com/camunda/camunda-bpm-platform/blob/7.10.0-alpha4/engine/src/test/java/org/camunda/bpm/engine/test/bpmn/tasklistener/TaskListenerTest.java#L125).

Can you please provide a test case with a model where the delete event is not triggered?

Cheers,
Thorben

Hm, seems you are right, false alarm … I took a step away from the code and created a minimal example, and it works. Must have been a lack of coffee.


public class TaskListenerOnBoundaryEventTest {

  private final static String TASK_DEFINITION_KEY = "test-task";
  private final static String END_SUCCESS = "success";
  private final static String END_INTERRUPT = "interrupted";
  private final static String MSG_INTERRUPT = "INTERRUPT";
  private static final String PROCESS_KEY = "test";

  // -- register two listeners --
  private final FluentTaskListenerMock onDelete = registerTaskListenerMock("onDelete");
  private final FluentTaskListenerMock onComplete = registerTaskListenerMock("onComplete");

  private ProcessInstance processInstance;
  private Task task;

  @Rule
  public final ProcessEngineRule camunda = new ProcessEngineRule(new StandaloneInMemProcessEngineConfiguration() {{
    jobExecutorActivate = false;
    expressionManager = new MockExpressionManager();
    databaseSchemaUpdate = DB_SCHEMA_UPDATE_DROP_CREATE;
    isDbMetricsReporterActivate = false;
    historyLevel = HistoryLevel.HISTORY_LEVEL_FULL;
  }}.buildProcessEngine());

  @Before
  public void generateAndDeployProcess() {
    camunda.manageDeployment(camunda.getRepositoryService().createDeployment()
      .addModelInstance(PROCESS_KEY + ".bpmn", Bpmn.createExecutableProcess(PROCESS_KEY)
        .startEvent()
        .userTask(TASK_DEFINITION_KEY)
        .camundaTaskListenerDelegateExpression(TaskListener.EVENTNAME_DELETE, "${onDelete}")
        .camundaTaskListenerDelegateExpression(TaskListener.EVENTNAME_COMPLETE, "${onComplete}")
        .boundaryEvent().message(MSG_INTERRUPT).endEvent(END_INTERRUPT)
        .moveToNode(TASK_DEFINITION_KEY)
        .endEvent(END_SUCCESS)
        .done())
      .deploy());
  }

  @Test
  public void onDelete_when_process_cancelled() {
    startProcess();

    camunda.getRuntimeService().deleteProcessInstance(processInstance.getProcessInstanceId(), "test");

    verifyTaskListenerMock(onComplete).executedNever();
    verifyTaskListenerMock(onDelete).executed();
  }

  @Test
  public void onComplete_when_task_completed() {
    startProcess();

    camunda.getTaskService().complete(task.getId());

    assertThat(processInstanceEndedWith()).isEqualTo(END_SUCCESS);

    verifyTaskListenerMock(onComplete).executed();
    verifyTaskListenerMock(onDelete).executedNever();
  }

  @Test
  public void onDelete_when_boundary() {
    startProcess();

    camunda.getRuntimeService().correlateMessage(MSG_INTERRUPT);

    assertThat(processInstanceEndedWith()).isEqualTo(END_INTERRUPT);

    verifyTaskListenerMock(onComplete).executedNever();
    verifyTaskListenerMock(onDelete).executed();
  }

  private void startProcess() {
    processInstance = camunda.getRuntimeService().startProcessInstanceByKey(PROCESS_KEY);
    task = camunda.getTaskService().createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).singleResult();

    assertThat(processInstanceEndedWith()).isNull();
    assertThat(task).isNotNull();

    // so far nothing happened
    verifyTaskListenerMock(onComplete).executedNever();
    verifyTaskListenerMock(onDelete).executedNever();
  }

  private String processInstanceEndedWith() {
    return camunda.getHistoryService().createHistoricProcessInstanceQuery().processInstanceId(processInstance.getProcessInstanceId())
      .singleResult()
      .getEndActivityId();

  }
}

see https://github.com/holunda-io/holunda-spike/tree/master/forum/task-delete-9302

1 Like