Not able to get processInstance details inside a listener

I’m trying to write a ProcessCompletedListener using flowable events.

Now inside the event, I’m trying to access variables associated with the processInstanceId.
To do that I tried to get the processDefinitionId using runtimeService and historicService. But both of these services are returning null.

    // Completed process, returns null; expected process is still running
    HistoricProcessInstance process = processEngine.getHistoryService().createHistoricProcessInstanceQuery()
            .processInstanceId(procInstanceId).singleResult();

    // Why is runtimeService also returning null ? 
    ProcessInstance processInstance = processEngine.getRuntimeService()
            .createProcessInstanceQuery()
            .processInstanceId(procInstanceId)
            .singleResult();

Getting processDefintionID was the first step in my process to get the variables associated with the processInstance. What service should I query in order to get processInstance variables/other-meta(processDefintionName, deploymentId) etc… inside a flowableEvent onEvent?

I have isFailOnException = true, isFireOnTransactionLifecycleEvent = false, getOnTransaction = null as override values for the event.

I found a work around, keeping isFireOnTransactionLifecycleEvent = true with getOnTransaction = “COMMITTED” worked for me.

Is there documentation detailing the getOnTransaction and it’s lifecycle?
I found some @ https://flowable.com/open-source/docs/bpmn/ch03-Configuration/#event-listener-implementation

The runtimeService query won’t check the cache. When the listener gets executed, the data hasn’t been committed yet to the database. That’s why it works when using the committed onTransaction event (but the listener will now not be part of the same database transaction).

You can query for the current execution in the listener and get the variables through the getVariable() methods. This depends on the type of listener. Can you post how the implementation for ProcessCompletedListener looks like?

Apologies that I couldn’t give you a prompt reply. @joram Here are my code snippets.

public interface ProcessEventsListener<T> extends FlowableEventListener {
    @Override
    default void onEvent(FlowableEvent flowableEvent) {
        handle((T) flowableEvent);
    }

    void handle(T event);

    @Override
    default boolean isFailOnException() {
        return true;
    }

    @Override
    default boolean isFireOnTransactionLifecycleEvent() {
        return true;
    }

    @Override
    default String getOnTransaction() {
        // Discussion on this is available here
        // https://forum.flowable.org/t/not-able-to-get-processinstance-details-inside-a-listener/6845/3
        // Turning this to COMMITTED as we have to latch on to HistoricalService/RuntimeService
        // Listener if fired otherwise won't find the RuntimeService/HistoricalService
        return "COMMITTED";
    }
}

And the completed listener looks like this.

@RequiredArgsConstructor(onConstructor = @__(@Inject))
public class ProcessCompletedListener implements ProcessEventsListener<FlowableEntityEventImpl> {

    private final WorkflowEventListenerService eventListenerService;
    private final WorkflowEngine workflowEngine;

    @Override
    public void handle(FlowableEntityEventImpl event) {
        ProcessCompletedEvent event1 = getEventContext((ProcessInstance) event.getEntity());
        eventListenerService.trigger(event1);
    }

    @SneakyThrows
    private ProcessCompletedEvent getEventContext(ProcessInstance processInstance) {
        String procInstanceId = processInstance.getId();
            
       // This is where I'm using HistoryService
        Map<String, Object> output = getProcessEngine().getHistoryService()
                .createHistoricVariableInstanceQuery()
                .processInstanceId(procInstanceId).list()
                .stream()
                .filter(histVar -> {
                    // some business logic filter outputs
                })
                .collect(toList);
        return ProcessCompletedEvent.builder()
                .processOutputs(workflowEngine.getRunVariables(procInstanceId, OUTPUT))
                .procInstanceId(procInstanceId)
                .procDefinitionId(processInstance.getProcessDefinitionId())
                .build();
    }
}

I couldn’t understand what you meant by the current execution object, what would be the function to get the current execution given processInstance id?

The process instance is an execution (a process instance is a root execution, consisting of multiple child executions). Since you have the process instance, you can pass it’s id in the runtimeService. But coming back to your original question: you would need to cast it down to a VariableScopeImpl to get access to the variables up to that point.

The reason why I was asking for the type of the listener is because you would need to have an event that received the process instance object (which you have, from the looks of it).

1 Like