Reliably detect Instance completion

I am looking for a reliable way to be notified when a process instance ends - either normally, or when it is cancelled.

The following code almost works, but when the instance contains a user task with multi instance, and the loop cardinality is greater than the nrOfCompletedInstances in the completion condition, the extra tasks seem to be cancelled, and my logic incorrectly thinks the instance was cancelled.

Can you help me come up with the correct logic to know when a process instance has completed or been cancelled?

@Component
@CamundaSelector(event = ExecutionListener.EVENTNAME_END)
public class EndEventExecutionListener extends ReactorExecutionListener {

    @Override
    public void notify(DelegateExecution delegateExecution) {

        if ((delegateExecution.getBpmnModelElementInstance() instanceof EndEvent) || delegateExecution.isCanceled()) {

            // Instance has completed or was cancelled...

        } else {

            // Instance continues to run ...

        }
    }
}

Hi @knotthere,

I would suggest you check for the activityId of the delegateExecution to be null in case of cancellation, that should yield the case where the process instance is canceled rather than any activity.

So this would then look like

@Component
@CamundaSelector(event = ExecutionListener.EVENTNAME_END)
public class EndEventExecutionListener extends ReactorExecutionListener {

    @Override
    public void notify(DelegateExecution delegateExecution) {

        if ((delegateExecution.getBpmnModelElementInstance() instanceof EndEvent) ||
            (delegateExecution.isCanceled() && delegateExecution.getCurrentActivityId() == null)) {

            // Instance has completed or was cancelled...

        } else {

            // Instance continues to run ...

        }
    }
}

Does that work for you?

Best regards,
Tobias

Thank you Tobias.
In the interim, I also figured out that this works:

@Component
@CamundaSelector(event = ExecutionListener.EVENTNAME_END)
public class EndEventExecutionListener extends ReactorExecutionListener {

    @Override
    public void notify(DelegateExecution delegateExecution) {

        // Instance ended or canceled?
        Boolean instanceEnded = delegateExecution.getBpmnModelElementInstance() instanceof EndEvent;
        DelegateExecution processInstance = delegateExecution.getProcessInstance();
        Boolean instanceCanceled = (processInstance != null) && processInstance.isCanceled();
        if (instanceEnded || instanceCanceled) {
            // Instance has completed or was cancelled...
        } else {
            // Instance continues to run ...
        }
    }
}