We use camunda as REST service in our app.
For completing user task in our app we have to make 2 actions:
1. Write data in local data base
2. Complete task by camunda rest API
But this operation is not transactional. It is a problem for us.
This code code is not transactional:
completeUserTask(String taskId, SpecificTaskData userData) {
dao.update(userData)
camundaRestApi.completeUserTask(taskId)
}
I see two available solution. Both split camunda user task to 2 nodes:
But i don’t like the idea creating service task or message receiver for each user tasks.
I think it makes a diagram unclear (more irrational).
What do you think about this problem? Thank you.
My advice is probably too late :-)
We also faced the problem about how to place both operation (writing business data and completing the task/sending message) in the same transaction.
Our solution is organize methods like this:
@Transactional
void correlate(String message, String businessKey, DataObject dataObject) {
dataRepository.update(dataObject);
runtimeService.correlateMessage(messageCode, businessKey);
}
Of course you can use any other triggers to continue the process flow (complete/submit user task).
Another approach is create execution listener which can get data from process context and put it into wherever you need (DAO, service, event bus, etc). Also by Java Config you can add such listener for any kind of activity by default (without specifying it in Modeler):
public class AddSendEventListenerToBpmnParseListener implements BpmnParseListener {
@Override public void parseProcess(Element processElement, ProcessDefinitionEntity processDefinition) {
processDefinition.addBuiltInListener(PvmEvent.EVENTNAME_START, new SendEventListener());
processDefinition.addBuiltInListener(PvmEvent.EVENTNAME_END, new SendEventListener()); }
@Override public void parseIntermediateThrowEvent(Element intermediateEventElement, ScopeImpl scope, ActivityImpl activity) {
activity.addBuiltInListener(PvmEvent.EVENTNAME_START, new SendEventListener()); }
@Override public void parseStartEvent(Element startEventElement, ScopeImpl scope, ActivityImpl startEventActivity) { }
// other methods omitted
}