Javax.transaction Problem on BPMN-Error with own transaction manager

Hello,

in our project we are using our own transaction Manager by using JtaProcessEngineConfiguration. We have successfully registered this transaction manager by reading this and this guide. So far so good. Now we have our own database, where we have saved our business-entities. These entities are also handled/manipulated in a camunda-bpmn-process. In the following i will call an entity “foo”. To concrete the scenario there is a javax.@transactional method like:

public class FooIncomingHandlerBean {

  // all relevant properties

  @Transactional
  public Foo fooIncoming(...) {
    Foo foo = new Foo();
    // .. code to prepare foo object by using ... parameters
    
    fooService.save(foo); // save foo object in our own db
    
    // startProcessInstanceByKey by using camunda RuntimeService 
    // and receive process instance id - works fine for each case (also with bpmn error)
    String processInstanceId = runtimeService.startProcessInstanceByKey("fooProcess");
    
    // we are saving the process instance id inside the foo entity
    foo.setProcessInstanceId(processInstanceId);

    // update foo in our own DB with the processInstanceId
    fooService.update(foo);
    // after that: If an bpmn error was thrown on starting, the foo-entity in our 
    // database is saved, but with processinstance id=null, otherwise it is set correctly
    return foo;
  }
}

To simplify the situation, let’s assume i have this simple process, where an bpmn error can be thrown:

The corresponding delegate Method is looking like this (note the transactional annotation as well):

@Transactional
public class DelegateDoSomething implements JavaDelegate {

    FooService fooService;
    
    @Override
    public void execute(DelegateExecution execution) throws Exception {
        Foo foo = fooService.findFoo(...);
        // ... manipulate foo and set some variables
        
        // throw bpmn error under some circumstances
        if(<someCondition>){
           throw new BpmnError("errorName");
        }
        // do the rest and update foo in our own database
        fooService.update(foo);
    }
}

Now i can explain the problem i have. When i run fooIncoming-method above and i run the processinstance and the bpmn-error is thrown, than the processInstanceId is correctly returned, but the updated process instance id is not saved in our database. What i figured out is, that this only happens if the bpmn error is thrown AND the javax. @transactional annotation is on the Delegate. So i guess the following happens:

Whenever a Bpmn-Error is thrown, the transaction manager is interpreting the BPMN Error as an Exception (Bpmn inherited from Exception), which is causing a roll back on our side. The Camunda is handling this error by going to the receiving task. So for the camunda engine there is no problem with that and it is returning the processinstance id. But because the javax.transaction has interpreted it as an exception the rollback is causing, that the processinstanceId is never set in our database - just in camunda-db.

The processinstance id has to be saved in each case for the foo entity in our own db. I have the following suggestions:

  1. Remove the transactional annotation in the delegate code (maybe it is duplicate, because camunda has registered our transaction manager?)
  2. adding @transactional(noRollBackOn=BpmnError.class)

Have you an idea how to handle this? Maybe it is just enough to register the transaction manager without the transactional annotation inside the delegates. I would be very glad for your help!

UPDATE: I have also seen, that we are setting the property for externally managed transactions inside the JTAConfiguration. Is this correct or is it enough, just to register the javax.transaction manager?

JtaProcessEngineConfiguration conf = new JtaProcessEngineConfiguration();
conf.setTransactionManager(transactionManager);
conf.setTransactionsExternallyManaged(true);

Thanks a lot and best regards,
Andy

Hi Andy,

Why you create new JtaProcessEngineConfiguration instance? Is it somewhere assigned to the process engine? Maybe you should use processEngine.getProcessEngineConfiguration() instead?

Regards,
Jacek