AnsweredAssumed Answered

Event after transaction with compensation

Question asked by nivertius on Dec 18, 2012
Greetings Activiti users and developers!

Consider following process definition:


<?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">
       <process id="transactionProcess">
      <startEvent id="start" />
      <sequenceFlow sourceRef="start" targetRef="transaction" />
      <transaction id="transaction">
         <startEvent id="startTransaction" />
         <sequenceFlow sourceRef="startTransaction" targetRef="taskNormal" />
         <userTask id="taskNormal" />
         <boundaryEvent id="eventCompensation" attachedToRef="taskNormal">
            <compensateEventDefinition />
         </boundaryEvent>
         <userTask id="taskCompensation" isForCompensation="true" />
         <sequenceFlow sourceRef="taskNormal" targetRef="endTransaction" />
         <endEvent id="endTransaction" />
         <association associationDirection="One" sourceRef="eventCompensation" targetRef="taskCompensation" />
      </transaction>
      <sequenceFlow sourceRef="transaction" targetRef="timer" />
     <intermediateCatchEvent id="timer">
         <timerEventDefinition>
            <timeDuration>P1D</timeDuration>
         </timerEventDefinition>
      </intermediateCatchEvent>
      <sequenceFlow sourceRef="timer" targetRef="end" />
      <endEvent id="end" />
       </process>
</definitions>

with following test case:


public void testTimerAfterTransaction() {
    Date startTime = new Date();
    ClockUtil.setCurrentTime(startTime);
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("transactionProcess");
    // the task is present
    Task task = taskService.createTaskQuery().singleResult();
    assertNotNull(task);
    // complete the tx
    taskService.complete(task.getId());
    List<String> activeActivityIds = runtimeService.getActiveActivityIds(processInstance.getId());
    assertTrue(activeActivityIds.contains("timer"));
    // trigger the timer
    ClockUtil.setCurrentTime(DateUtils.addDays(startTime, 1));
    job = managementService.createJobQuery().executable().singleResult();
    assertNotNull(job);
    managementService.executeJob(job.getId());
    // end the process instance
    assertProcessEnded(processInstance.getId());
    assertEquals(0, runtimeService.createExecutionQuery().count());
}

In simple words, that's a transaction in which there is a simple user task with compensation, and timer event with set period.
Testcase executes simplest possible scenario: completes task in transaction, forwards time to trigger timer and executes timer job, after which process should end.

However, process does not end - there's a execution waiting in 'transaction' activity and it doesn't show in query for specific process instance executions.
Same error occurs for intermediateCatchEvent with messageEventDefinition.
When there's no compensation (ex. missing 'association' element) or there's no timer - process completes normally.

Simple fix for this is be noop service task with activiti:async="true" between transaction and timer - this fixes the testcase.

From my quick debugging I think the problem is that execution is actually created for compensation event which is not handled, but I could be plain wrong here.

Am I missing something, doing something wrong, or is there a bug in Activiti?

Outcomes