Tasks of a nested case instance terminated by message correlation stay active

A case instance is terminated by terminating the parent process instance via message correlation triggering a terminating event.

The case instance itself spawned a human task that is still active after the parent process and the case instance itself is already terminated.

This also makes it impossible to “complete” the task, though that should probably not be an option anyway, triggering a NullPointerException as the superExecution is gone:

Caused by: java.lang.NullPointerException
	at org.camunda.bpm.engine.impl.cmmn.entity.runtime.CaseExecutionEntity.setSuperExecution(CaseExecutionEntity.java:468)
	at org.camunda.bpm.engine.impl.cmmn.operation.AbstractAtomicOperationCaseExecutionComplete.postTransitionNotification(AbstractAtomicOperationCaseExecutionComplete.java:98)
	at org.camunda.bpm.engine.impl.cmmn.operation.AbstractCmmnEventAtomicOperation.eventNotificationsCompleted(AbstractCmmnEventAtomicOperation.java:40)
	at org.camunda.bpm.engine.impl.cmmn.operation.AbstractCmmnEventAtomicOperation.eventNotificationsCompleted(AbstractCmmnEventAtomicOperation.java:26)
	at org.camunda.bpm.engine.impl.core.operation.AbstractEventAtomicOperation.execute(AbstractEventAtomicOperation.java:65)
	at org.camunda.bpm.engine.impl.cmmn.operation.AbstractCmmnEventAtomicOperation.execute(AbstractCmmnEventAtomicOperation.java:26)
	at org.camunda.bpm.engine.impl.interceptor.CommandContext.performOperation(CommandContext.java:214)

I’m not sure wether I’m doing something wrong so the termination of tasks is not triggered or if this is inadvertent behavior. I created a Unit test that may be helpful.

In my application I tried to do a simple workaround to delete case tasks before correlating the kill message like this:

final List<String> taskIds = taskService
                    .createTaskQuery().caseInstanceBusinessKey(businessKey).list()
                    .stream().map(Task::getId).collect(Collectors.toList());
taskService.deleteTasks(taskIds);

But that isn’t possible as the engine triggers:

org.camunda.bpm.engine.ProcessEngineException: The task cannot be deleted because is part of a running case instance
	at org.camunda.bpm.engine.impl.cmd.DeleteTaskCmd.deleteTask(DeleteTaskCmd.java:73)

I’m not sure how to get rid of these tasks now.

EDIT:

I was wondering wether manually closing the case instance would be a solution here:

// Then the process instance should be ended
assertThat(processInstance.isEnded());

// as well as the case instance
assertThat(!caseInstance.isActive());
assertThat(!caseInstance.isCompleted());
assertThat(caseInstance.isTerminated());

caseService.closeCaseInstance(caseInstance.getId()); // throws exception

But while the above assertions succeed, the following exception is thrown closing the instance:

org.camunda.bpm.engine.exception.NotAllowedException: ENGINE-05008 Could not perform transition 'close on case execution with id '11'.Reason: The case instance must be in state '[completed|terminated|suspended]' to close it, but the state is 'active'.

at org.camunda.bpm.engine.impl.cmmn.CaseExecutionCommandBuilderImpl.executeCommand(CaseExecutionCommandBuilderImpl.java:237)
at org.camunda.bpm.engine.impl.cmmn.CaseExecutionCommandBuilderImpl.close(CaseExecutionCommandBuilderImpl.java:218)
at org.camunda.bpm.engine.impl.cmmn.CaseServiceImpl.closeCaseInstance(CaseServiceImpl.java:263)
at org.camunda.bpm.unittest.SimpleTestCase.shouldExecuteProcess(SimpleTestCase.java:93)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:55)

It looks like the case instance is in limbo between being active, terminated and closed with dangling tasks still active in the runtime database.

Hi @bentrm,

Thanks for reporting the NullPointerException. I created a bug ticket therefore: CAM-6765

This does not happen. In that case the case instance remains active and do not get completed or terminated. The reason for that is, it is not specified in the BPMN specification :wink:
A workaround for that would be, that you could add an execution listener on the interrupting boundary event. The execution listener could trigger the completion (or termination) of the called case instance.

Regarding to your assertions in your test case, I think that they are not correct, because assertThat(...) returns always true. You have to say assertThat(...).isTrue() etc., then you will see, that the case instance is still active and not terminated. BTW after performing the correlation, you have to fetch the case instance again from the database to get the current state of it.

Cheers,
Roman

This is very helpful, thank you very much! Found an actual bug with incorrect unit tests, made it pretty hard for me to understand whats going on.

Regarding to your assertions in your test case, I think that they are not correct, because assertThat(…) returns always true.

:neutral_face:

Well, thats something. My mind was set on assertTrue the whole time… Why the heck does assertThat(false) return true without a matcher though…