JpaSagaRepository missing a transaction on add(Saga)

When using the JpaSagaRepository I get
javax.persistence.TransactionRequiredException: no transaction is in progress
when the saga is added to the repository. I’m guessing a transaction is needed when adding the sagas as storeAssociationValue is persisting association values.
I’m not sure what to wrap in a transaction?

Caused by: javax.persistence.TransactionRequiredException: no transaction is in progress
at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:792)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:365)
at $Proxy44.flush(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
at $Proxy44.flush(Unknown Source)
at org.axonframework.saga.repository.jpa.JpaSagaRepository.storeAssociationValue(JpaSagaRepository.java:111)
at org.axonframework.saga.repository.AbstractSagaRepository.add(AbstractSagaRepository.java:89)
at org.axonframework.saga.repository.jpa.JpaSagaRepository.add(JpaSagaRepository.java:74)
at org.axonframework.saga.annotation.AnnotatedSagaManager.findSagas(AnnotatedSagaManager.java:122)
at org.axonframework.saga.annotation.AnnotatedSagaManager.findSagas(AnnotatedSagaManager.java:103)
at org.axonframework.saga.AbstractSagaManager$SagaLookupAndInvocationTask.run(AbstractSagaManager.java:227)
at org.axonframework.saga.SynchronousSagaExecutionWrapper.scheduleLookupTask(SynchronousSagaExecutionWrapper.java:29)
at org.axonframework.saga.AbstractSagaManager.handle(AbstractSagaManager.java:86)
at org.axonframework.eventhandling.SimpleCluster.publish(SimpleCluster.java:34)
at com.tuckerten.platform.sharedintegration.AMQPEventBusTerminal.handleMessage(AMQPEventBusTerminal.java:55)
… 17 more

Hi Ted,

I notice you are reading the event from AMQP. Is there any transactional boundary (starting a database transaction using Spring’s PlatformTransactionManager, for example) somewhere in between the AMQP connection and the saga manager?

It sounds like you might want to add some transactional logic in your EventBusTerminal. You’ll want to start a transaction before sending your events to the Clusters, and committing them once dispatched.

Hope this helps.

Cheers,

Allard

PS. Sounds like there is use for a “TransactionalCluster”…

Something like this?

public class SpringTransactionalCluster extends SimpleCluster {
private PlatformTransactionManager transactionManager;
private TransactionDefinition transactionDefinition;

@Override
public void publish(Event event) {
TransactionStatus status = transactionManager.getTransaction(transactionDefinition);
super.publish(event);
if (status.isNewTransaction()) {
transactionManager.commit(status);
}
}

/**

  • Sets the transaction manager that manages the transaction around the publication of an event. If a transaction
  • manager is not specified, no transactions are managed around the event publication.

That’s it, yeah.
Be careful though with possible exceptions from super.publish(event);. If that method throws an exception, the transaction stays active. You’ll either want to roll back and retry the event later (transient exceptions), or commit and disregard the failed message (non-transient exceptions).

Cheers,

Allard