Activiti and database transactions

In my current project we use Activiti as a business process orchestrator. Recently we ran into problems with database transactions. We had webservice calls to an external in one of process steps (service task). We wanted to have everything committed before the call, just in case the webservice fails. Ideally, every process step should be executed in a separate transaction

We (naively) thought every service task was wrapped into an individual transaction. We discovered that there was one big transaction spanning the entire process.

This blog post is a recording of spikes I did to understand when transactions are started and completed in Activiti processes.

Initial configuration

In our Grails application Activiti ProcessEngine was configured with SpringProcessEngineConfiguration. It requires a Spring TransactionManager. We duly supplied the manager created by Grails.

Transaction demarcation

According to the documentation

The ProcessEngineFactoryBean will have added an extra interceptor to the services that applies Propagation.REQUIRED transaction semantics on the Activiti service methods.

It implies:
* every Activiti service is transactional (RuntimeService, RepositoryService, etc.). It either starts a transaction or participates in an existing one.
* if RuntimeService is used to launch a process, every service task during the process execution ‘inherits’ the transaction from the RuntimeService
* same transaction for the duration of the process execution

Service tasks – how to get control of transactions?

Use REQUIRES_NEW semantics

Mark service classes or individual methods methods as @Transactional(propagation = Propagation.REQUIRES_NEW).

Note: be careful when mixing process steps participating in the ‘parent’ transaction triggered by the RuntimeService and those wrapped in their own transaction. If the ‘parent’ transaction is rolled back, individual transactions may be committed. If service tasks with individual transactions depend on some modifications made before (in tasks inside the ‘parent’ transaction) the changes may not be visible to them.

StandaloneProcessEngineConfiguration

Configure process engine with StandaloneProcessEngineConfiguration.

Once again, documentation says it clearly:

the process engine is used in a standalone way. Activiti will take care of the transactions.

The configuration is simple:

However, you lose the automatic deployment of processes. This could be mend by borrowing the code from the org.activiti.spring.SpringProcessEngineConfiguration#autoDeployResources method.

Advertisements