Java – ActiveMQ: dead letter queue keeps my message order
I use ActiveMQ as a proxy to deliver messages These messages are written in dabatase Sometimes, the database cannot be accessed or closed In this case, I want to roll back my message so that I can retry this message later. I want to continue reading other messages
This code works well except that the rollback message prevents me from reading other code:
private Connection getConnection() throws JMSException { RedeliveryPolicy redeliveryPolicy = new RedeliveryPolicy(); redeliveryPolicy.setMaximumRedeliveries(3); // will retry 3 times to dequeue rollbacked messages redeliveryPolicy.setInitialRedeliveryDelay(5 *1000); // will wait 5s to read that message ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(user,password,url); Connection connection = connectionFactory.createConnection(); ((ActiveMQConnection)connection).setUseAsyncSend(true); ((ActiveMQConnection)connection).setDispatchAsync(true); ((ActiveMQConnection)connection).setRedeliveryPolicy(redeliveryPolicy); ((ActiveMQConnection)connection).setStatsEnabled(true); connection.setClientID("myClientID"); return connection; }
I create a session this way:
session = connection.createSession(true,Session.SESSION_TRANSACTED);
Rollback is easy to ask:
session.rollback();
Suppose there are 3 messages in my queue:
1: ok 2: KO (will need to be treated again : the message I want to rollback) 3: ok 4: ok
What will my consumer do (linear sequence):
commit 1 rollback 2 wait 5s rollback 2 wait 5s rollback 2 put 2 in dead letter queue (ActiveMQ.DLQ) commit 3 commit 4
But I want to:
commit 1 rollback 2 commit 3 commit 4 wait 5s rollback 2 wait 5s rollback 2 wait 5s put 2 in dead letter queue (ActiveMQ.DLQ)
So how do I configure my consumer to delay my rollback messages later?
Solution
This is actually the expected behavior because message retries are handled by the client rather than the agent Therefore, because you have 1 session binding and have set a retry policy for 3 retries before dlq, the whole retry process will block the specific thread
So, my first question is, if the database insertion fails, do you want all other databases to fail for similar reasons?
If not, the way to solve this problem is to set the retry policy of the queue to 0 retries with a specific dlq, so that the message fails immediately and enters the dlq Then another process takes it out of the dlq every 5 seconds and reprocesses it and / or puts it back to the main queue for processing