JpaSagaRepository missing a transaction on add(Saga)

257 views
Skip to first unread message

Ted Steen

unread,
Nov 10, 2011, 2:31:55 PM11/10/11
to axonfr...@googlegroups.com
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

Allard Buijze

unread,
Nov 10, 2011, 2:57:44 PM11/10/11
to axonfr...@googlegroups.com
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"....

Ted Steen

unread,
Nov 10, 2011, 4:23:42 PM11/10/11
to axonfr...@googlegroups.com
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.
     *
     * @param transactionManager the transaction manager that takes care of transactions around event publication
     */
    public void setTransactionManager(PlatformTransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }

    /**
     * The TransactionDefinition to use by the transaction manager. Default to a {@link
     * org.springframework.transaction.support.DefaultTransactionDefinition}.
     * Is ignored if no transaction manager is configured.
     *
     * @param transactionDefinition the TransactionDefinition to use by the transaction manager
     */
    public void setTransactionDefinition(TransactionDefinition transactionDefinition) {
        this.transactionDefinition = transactionDefinition;
    }
}




Then we need something a little more generic than DefaultClusterSelector
Like this?

public class SimpleClusterSelector implements ClusterSelector {
    private final Cluster defaultCluster;

    public SimpleClusterSelector(Cluster defaultCluster) {
        this.defaultCluster = defaultCluster;
    }

    @Override
    public Cluster selectCluster(EventListener eventListener) {
        return defaultCluster;
    }
}



2011/11/10 Allard Buijze <bui...@gmail.com>

Allard Buijze

unread,
Nov 10, 2011, 4:41:19 PM11/10/11
to axonfr...@googlegroups.com
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
Reply all
Reply to author
Forward
0 new messages