ActiveMQ Artemis Brokers behavior on trasaction commit error due to failover

Viewed 34

We have encountered the following problem aka TransactionRolledBackException:

Transaction completion in doubt due to failover. Forcing rollback of ID:*****  at Apache.NMS.ActiveMQ.Connection.SyncRequest(Command command, TimeSpan requestTimeout)
   at Apache.NMS.ActiveMQ.Connection.SyncRequest(Command command)
   at Apache.NMS.ActiveMQ.TransactionContext.Commit()
   at Apache.NMS.ActiveMQ.Session.DoCommit()
   at Apache.NMS.ActiveMQ.Session.Commit() 

Here's our topology: we have 6 nodes (n1, .., n6) where nodes n1, n3, n5 are clustered master nodes, and n2 is slave of n1, n4 is slave of n3, n6 is slave of n5.

We use transactions in sending and consuming message processes, which means that this exception could be thrown in both. I'm looking for best practices of handling TransactionRolledBackException without needing to rollback all the business logic executed before commit. We have our own application-level library, which allows fast and easy connection to the broker for sending/receiving messages, and we would like to implement into it some code which would handle TransactionRolledBackException for every application using it and provide "once and only once" delivery.

Thanks for your answers in advance

1 Answers

The transaction itself is there to provide the guarantees you're looking for (i.e. "once and only once").

Typically in the kind of situation you describe (where the consumption or production of a message or groups of messages needs to happen atomically with other business operations) all the resources involved in the atomic operation (e.g. JMS consumption, JMS production, JDBC inserts, JDBC deletes, etc.) are enlisted into the same transaction and managed by a transaction manager. That way when one of the individual operations fails then all the other work is automatically undone as well. Transactions like this are typically called XA transactions and are supported in both Spring and Java EE via the Jakarta/Java Transactions API (i.e. JTA).

In Java EE it is very common, for example, to have a Message Driven Bean (i.e. MDB) consume a message, work with a database, and then send another message so that every piece of that work is done atomically. If sending the message at the end fails then the database changes are reversed and the message the MDB consumed originally is put back on the queue to be consumed again in the future. In this way the message represents a kind of "unit of work" which is a simple, powerful pattern for managing business processes.

Related