Triggerable Task Results in 2 Jobs for the Subsequent Activity

Dear Flowable experts,

In our implementation, we have extended the org.flowable.engine.impl.bpmn.behavior.TaskActivityBehavior. In this extension, the execute method does nothing apart from some internal bookkeeping and does not call the AbstractBpmnActivityBehavior#leave function. Whereas, the trigger method is implemented as follows:

    @Override
    public void trigger(DelegateExecution execution, String signalName, Object signalData) {
        leave(execution);
    }

When implementing the logic which would result in the completion of the above mentioned task, we first relied on the following function: CommandContextUtil.getAgenda().planTriggerExecutionOperation(execution). However, we observed that this resulted in 2 jobs (records in the ACT_RU_JOB table) responsible for the execution of the subsequent activity. As a result, they competed with each other and lead to a FlowableOptimisticLockingException. Eventually, they could somehow cope with each other, but it didn’t seem like an expected behavior to us.

After switching to the CommandContextUtil.getAgenda().planTakeOutgoingSequenceFlowsOperation(execution, false) instead of the planTriggerExecutionOperation, the phenomenon has been gone and there has only been one Job created for the subsequent activity, as expected.

In all sources we find, the first approach is described as a conventional way to go. But we are not quite sure, why it does not apply to our implementation.

Could you please assist us here? Do you maybe have a suspicion why the first approach results in the above mentioned phenomenon? What would be the proper way to go?

It is worth mentioning that all flow elements in our processes are modeled as asynchronous and exclusive (the 2 jobs mentioned above are also both exclusive). Using planAsyncTriggerExecutionOperation or RuntimeService#triggerAsync instead of planTriggerExecutionOperation also resulted in 2 jobs for the subsequent activity.

We have now an additional finding that leaving the implementation of the trigger method empty also results in the phenomenon to disappear. Is this the conventional way then:

  • Empty implementation of the trigger method in the ActivityBehavior extension
  • planAsyncTriggerExecutionOperation, RuntimeService#triggerAsync, or CommandContextUtil.getAgenda().planTriggerExecutionOperation(execution) for activity completion
    ?