Jms message acknowledge only till the message acknowledged on

Raks picture Raks · Dec 6, 2011 · Viewed 7.4k times · Source

How to ensure message acknowledge deletes only messages upto the message on which acknowledge is called in a jms broker. Currently I have a system which consumes from a jms queue and partially processes it.Sometime later a batch of these messages gets persisted by a different thread. I need to acknowledge on messages now. But the problem is I have to stop consuming the messages, otherwise acknowledging a previously received message will also acknowledge all other subsequent messages received.

In other words suppose I have 10 messages in a queue. I consume 7 of them, and then acknowledge on 5th message. This in turn removes all 7 messages received by consumer from the queue.Is there a way to only acknowledge and remove messages from queue till 5th message.

EDIT: I have tried creating two sessions and consuming from different sessions, but (with apache qpid atleast) this performs inconsistently. By inconsistently I mean, sometimes during the test it so happens that one consumer is able to receive messages, while the other doesn't receive at all, no matter how long you wait. This would have worked for me as a solution, but because of inconsistency can't use this as a solution.

Answer

Deepak Bala picture Deepak Bala · Feb 21, 2014

I understand this post is old, but this answer should benefit those who stumble upon it later.

If you'd like fine grained control of which messages you'd like to acknowledge, the individual acknowledge method should help you. Using this acknowledgement mode you can ack individual messages in a session. Messages that have not been ack-ed will be redelivered.

This is not part of the spec, but most queue providers support it outside the spec.

Oracle

For more flexibility, Message Queue lets you customize the JMS client-acknowledge mode. In client-acknowledge mode, the client explicitly acknowledges message consumption by invoking the acknowledge() method of a message object.

The standard behavior of this method is to cause the session to acknowledge all messages that have been consumed by any consumer in the session since the last time the method was invoked. (That is, the session acknowledges the current message and all previously unacknowledged messages, regardless of who consumed them.)

In addition to the standard behavior specified by JMS, Message Queue lets you use client-acknowledge mode to acknowledge one message at a time.

public interface com.sun.messaging.jms.Message {
          void acknowledgeThisMessage() throws JMSException;
          void acknowledgeUpThroughThisMessage() throws JMSException;
}

ActiveMQ

One can imagine other acknowledge modes that would be useful too, for example: CONSUMER_ACKNOWLEDGE where Message.acknowledge() would acknowledge only messages received up on a particular MessageConsumer, or CONSUMER_CHECKPOINT_ACKNOWLEDGE where Message.acknowledge() would acknowledge only messages received up to and including the Message instance on which the method was called.

But without embarking on all these various different possibilities, would it be possible to consider just adding INDIVIDUAL_ACKNOWLEDGE mode? This alone would make it possible for multithreaded applications to achieve whatever behaviors they need.

connection.createQueueSession(false, ActiveMQSession.INDIVIDUAL_ACKNOWLEDGE);

I have not used QPID personally, however the documentation hints to the fact that individual message acks are possible.

Examples
  # acknowledge all received messages
  session.acknowledge

  # acknowledge a single message
  session.acknowledge :message => message

While processing a batch you can ack each message that is received and processed. If you encounter an exception, do not ack the message.