Redeliver JMS message from ActiveMQ Artemis queue

45 Views Asked by At

I am currently implementing a consumer which listens to events sent by an ActiveMQ Artemis Broker.

I've found this article which says:

The main difference between 1 & 2 and 3 & 4 is the latter allow messages to be rolled back and redelivered if an error occurs whilst processing

So I assume a redelivery with 1 & 2 (Client Acknowledgement) is not possible.

Here in the docu from Apache it is said

Messages can be delivered unsuccessfully (e.g. if the transacted session used to consume them is rolled back)

I assume CLIENT_ACKNOWLEDGE is no transaction so this isn't valid for, correct?

So if I set lets say <redelivery-delay>300000</redelivery-delay> there will be any message redelivery after 5 Minutes?

The Spring Documentation here says:

"sessionAcknowledgeMode" set to "CLIENT_ACKNOWLEDGE": Automatic message acknowledgment after successful listener execution; best-effort redelivery in case of a user exception thrown as well as in case of other listener execution interruptions (such as the JVM dying).

This is a bit confusing. I have found also this configuration for ActiveMQ Artemis so I have these questions:

  1. Is a redelivery possible with CLIENT_ACKNOWLEDGE
  2. If yes, what is the difference between a redelivery with @Transactional and an omitted Message.acknowledge() call? Which should I prefer when over the other?
  3. If no, what does the Spring documentation actually mean?
2

There are 2 best solutions below

0
Doug Grove On

For a message to be redelivered, the Artemis message broker must be aware that the message needs to be redelivered.

In the case of CLIENT_ACKNOWLEDGE mode, there are no timeouts, but the JMS session could fail for a variety of reasons. For example, start up your client, consume but do not acknowledge the messages. Then kill your client (terminate the java process). The messages will be available for delivery/redelivery.

In the case of a transacted session, if the transaction context fails (times out, etc.) then the message will once again be available for delivery. The same conditions also apply as above to the session failing in the transacted case.

0
Justin Bertram On

This documentation you cited from ActiveMQ Classic is misleading:

There are four main approaches as to a client can consume messages. They are:

  1. Auto-acknowledgement
  2. Explicit acknowledgement via Message.acknowledge()
  3. JMS Transactions
  4. XA

...

The main difference between 1 & 2 and 3 & 4 is the latter allow messages to be rolled back and redelivered if an error occurs whilst processing. There is no JMS ‘unacknowledge’. So for this reason JMS transactions should be preferred to message acknowledgements in most use cases.

The fact is, Message.acknowledge() is orthogonal to using JMS transctions. In other words, you can use Message.acknowledge() with a transaction or without a transaction.

If you use Message.acknowledge() with a transaction then rollback() on the JMS Session may cause a redelivery of the message depending on how the broker is configured. I stop short of saying that rolling back the Session will always cause a redelivery because in some cases the broker may send the message to a dead-letter queue or potentially remove it entirely (e.g. if the message has already been redelivered "too many" times).

If you use Message.acknowledge() without a transaction then the message will be removed from the queue without chance of later recovery. Of course, that assumes the acknowledgement actually makes it across the network to the broker. There might be a network error or the JVM might die (for whatever reason) before the acknowledgement can be sent in which case even though your application invoked Message.acknowledge() the message will not be acknowledged. I believe this is essentially what the Spring documentation is referring to. Redelivery is possible with CLIENT_ACKNOWLEDGE if the Session is closed without acknowledging the message.

Whether you use a transacted session or CLIENT_ACKNOWLEDGE you must always, at the very least, invoke Message.acknowledge() if you want to acknowledge the message.

Whether you prefer to use a transacted session depends on entirely on your use-case.