cancel
Showing results for 
Search instead for 
Did you mean: 

NullPointerException in AtomicOperationTransitionDestroyScope

deg
Champ in-the-making
Champ in-the-making
In activiti 5.16.3 we defined a flow that has a receive task.
Later on in the flow it is possible to be redirected to that same receive task.

In our integration tests we test the flow by signalling  the execution

runtimeService.signal(id, processData);

Since it is possible in our flow that the same recieve task needs to notified twice we signal it again.
Due to an oversight on our part we did this without waiting for the process to be in the correct waiting state.
This gives us a strange exception:

Caused by: java.lang.NullPointerException: null
        at org.activiti.engine.impl.pvm.runtime.AtomicOperationTransitionDestroyScope.execute(AtomicOperationTransitionDestroyScope.java:96) ~[activiti-engine-5.16.3.jar:5.16.3]
        at org.activiti.engine.impl.interceptor.CommandContext.performOperation(CommandContext.java:96) ~[activiti-engine-5.16.3.jar:5.16.3]
        at org.activiti.engine.impl.persistence.entity.ExecutionEntity.performOperationSync(ExecutionEntity.java:621) ~[activiti-engine-5.16.3.jar:5.16.3]
        at org.activiti.engine.impl.persistence.entity.ExecutionEntity.performOperation(ExecutionEntity.java:616) ~[activiti-engine-5.16.3.jar:5.16.3]
        at org.activiti.engine.impl.pvm.runtime.AtomicOperationTransitionNotifyListenerEnd.eventNotificationsCompleted(AtomicOperationTransitionNotifyListenerEnd.java:35) ~[activiti-engine-5.16.3.jar:5.16.3]
        at org.activiti.engine.impl.pvm.runtime.AbstractEventAtomicOperation.execute(AbstractEventAtomicOperation.java:56) ~[activiti-engine-5.16.3.jar:5.16.3]
        at org.activiti.engine.impl.interceptor.CommandContext.performOperation(CommandContext.java:96) ~[activiti-engine-5.16.3.jar:5.16.3]
        at org.activiti.engine.impl.persistence.entity.ExecutionEntity.performOperationSync(ExecutionEntity.java:621) ~[activiti-engine-5.16.3.jar:5.16.3]
        at org.activiti.engine.impl.persistence.entity.ExecutionEntity.performOperation(ExecutionEntity.java:616) ~[activiti-engine-5.16.3.jar:5.16.3]
        at org.activiti.engine.impl.pvm.runtime.AbstractEventAtomicOperation.execute(AbstractEventAtomicOperation.java:49) ~[activiti-engine-5.16.3.jar:5.16.3]
        at org.activiti.engine.impl.interceptor.CommandContext.performOperation(CommandContext.java:96) ~[activiti-engine-5.16.3.jar:5.16.3]
        at org.activiti.engine.impl.persistence.entity.ExecutionEntity.performOperationSync(ExecutionEntity.java:621) ~[activiti-engine-5.16.3.jar:5.16.3]
        at org.activiti.engine.impl.persistence.entity.ExecutionEntity.performOperation(ExecutionEntity.java:616) ~[activiti-engine-5.16.3.jar:5.16.3]
        at org.activiti.engine.impl.persistence.entity.ExecutionEntity.take(ExecutionEntity.java:440) ~[activiti-engine-5.16.3.jar:5.16.3]
        at org.activiti.engine.impl.persistence.entity.ExecutionEntity.take(ExecutionEntity.java:418) ~[activiti-engine-5.16.3.jar:5.16.3]
        at org.activiti.engine.impl.bpmn.behavior.BpmnActivityBehavior.performOutgoingBehavior(BpmnActivityBehavior.java:131) ~[activiti-engine-5.16.3.jar:5.16.3]
        at org.activiti.engine.impl.bpmn.behavior.BpmnActivityBehavior.performDefaultOutgoingBehavior(BpmnActivityBehavior.java:64) ~[activiti-engine-5.16.3.jar:5.16.3]
        at org.activiti.engine.impl.bpmn.behavior.FlowNodeActivityBehavior.leave(FlowNodeActivityBehavior.java:44) ~[activiti-engine-5.16.3.jar:5.16.3]
        at org.activiti.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior.leave(AbstractBpmnActivityBehavior.java:47) ~[activiti-engine-5.16.3.jar:5.16.3]
        at org.activiti.engine.impl.bpmn.behavior.ReceiveTaskActivityBehavior.signal(ReceiveTaskActivityBehavior.java:35) ~[activiti-engine-5.16.3.jar:5.16.3]
        at org.activiti.engine.impl.persistence.entity.ExecutionEntity.signal(ExecutionEntity.java:397) ~[activiti-engine-5.16.3.jar:5.16.3]
        at org.activiti.engine.impl.cmd.SignalCmd.execute(SignalCmd.java:43) ~[activiti-engine-5.16.3.jar:5.16.3]
        at org.activiti.engine.impl.cmd.NeedsActiveExecutionCmd.execute(NeedsActiveExecutionCmd.java:55) ~[activiti-engine-5.16.3.jar:5.16.3]
        at org.activiti.engine.impl.interceptor.CommandInvoker.execute(CommandInvoker.java:24) ~[activiti-engine-5.16.3.jar:5.16.3]
        at org.activiti.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:57) ~[activiti-engine-5.16.3.jar:5.16.3]
        at org.activiti.spring.SpringTransactionInterceptor$1.doInTransaction(SpringTransactionInterceptor.java:47) ~[activiti-spring-5.16.3.jar:5.16.3]
        at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:131) ~[spring-tx-3.2.8.RELEASE.jar:3.2.8.RELEASE]
      
By adding the check to verify if the process is waiting we can avoid the exception.
But it took us a while to find out what was wrong, you don't expect nullpointers like that.
Also troubling was the fact that it seemed to break all of the running activiti process.
Other integration tests suddenly also failed.

Update:
Entering Thread.sleep in our test code seems to resolve it
But that's not an ideal solution.
Any idea's?
2 REPLIES 2

deg
Champ in-the-making
Champ in-the-making
In Activiti 5.17 we still encounter this:

We wait for the process to wait for the event before we send the message.
We do this by querying the proces so that it is in the receive task before we send the message.
<code>
runtimeService.createExecutionQuery()
                .processDefinitionKey(processDefinitionKey)
                .activityId(taskIdentifier)
                .processVariableValueEquals(A_KEY, aUniqueValue);
</code>
When this query returns the result we signal the process that the task is received. But this still gives us the error.
<code>
Caused by: java.lang.NullPointerException: null
at org.activiti.engine.impl.pvm.runtime.AtomicOperationTransitionDestroyScope.execute(AtomicOperationTransitionDestroyScope.java:96) ~[activiti-engine-5.17.0.jar:5.17.0]
at org.activiti.engine.impl.interceptor.CommandContext.performOperation(CommandContext.java:96) ~[activiti-engine-5.17.0.jar:5.17.0]
at org.activiti.engine.impl.persistence.entity.ExecutionEntity.performOperationSync(ExecutionEntity.java:631) ~[activiti-engine-5.17.0.jar:5.17.0]
</code>

If we add the ugly:
<code>Thread.sleep(1000);</code>
then our tests pass.

But i really don't want such fragile tests with Thread.sleeps everywhere.

jbarrez
Star Contributor
Star Contributor
That is a racing condition between the receive task database commit and the signal method.
I agree a nullpointer is not nice, but it would still be the same issue with a nicer message.
If you signal that quickly, why not use another construct (a custom service task for example that does the wait and receive at once?)