Transaction management and propagation modes in Flowable

Hi,

I’m running into the following problem. I use the TaskService to fetch tasks using a custom native task query. In the same method, the process variables are fetched for each task, since we cannot do this in the same query (as far as I know). Now we run into problems when one of these tasks is being completed in between fetching all the tasks we need and fetching their process variables.

First attempt
So I’ve analysed the situation, and what happens is that Flowable uses the transaction my code has started, and then taskService.getVariables throws an ActivitiObjectNotFoundException, which marks the same transaction we are using. My first attempt was pretty naive, just catching the exception without thinking that this might be a problem with transactions.

try {
  Map<String, Object> variables = taskService.getVariables(task.getId());
  return mapActivitiTask(task, variables);
} catch (ActivitiObjectNotFoundException e) {
  logger.info("Error occurred when obtaining variables for task. This is a racecondition in retrieving the task list! Original message: {}", e.getMessage());
  return null;
}

Now, as earlier described, this obviously doesn’t work. In the next iteration of the loop, an exception is thrown that we try to use a transaction that has already been aborted.

Second attempt
So as a second attempt, and with what I’ve learned, I tried doing something else. As we are only reading tasks, why even bother starting a transaction? I just marked the method that might suffer from this problem with a different propagation.

@Transactional(propagation = Propagation.NOT_SUPPORTED)

And this seems to work. Flowable has its own transaction and my code does not. When we encounter a Task whose variables are not found, we simply leave it out of the result.

Third attempt
The third attempt is by using the managementService, and passing in a custom CommandConfig. This also seems to work.

Map<String, Object> variables = managementService.executeCommand(
							new CommandConfig().transactionNotSupported(),
							new GetTaskVariablesCmd(task.getId(), null, false));

My question
While my last two attempts work, I’m unsure which one is the best, and what the pitfalls are I should watch out for. The last attempt seems the most clean to me, by just telling Flowable to not use a transaction when getting the taskVariables.

I’d like some input on this if possible.

Hi,

You can fetch the variables together with the task query.
Have a look at:

https://github.com/flowable/flowable-engine/blob/master/modules/flowable-engine/src/main/resources/org/flowable/db/mapping/entity/Task.xml

The selectTaskWithVariablesByQueryCriteriaColumns sql statement shows how to fetch the variables together with the tasks. In the TaskQuery there’s also an includeProcessVariables option to enable this. You could do a similar thing in a native query.

Best regards,

Tijs