3
votes

I read this question(Multithreaded JMS code : CLIENT_ACKNOWLEDGE or transacted session) but I didn't understand What is the difference between these two methods in message consumer:

  1. the connection is not transacted. the session is in CLIENT_ACKNOWLEDGE mode. We receive multiple messages, then one acknowledge().
  2. the connection is transacted(not xa). the session is in AUTO_ACKNOWLEDGE mode. we receive multiple messages, then do a commit().

Is this depends on message provider behavior?

2

2 Answers

2
votes

I think there is not much difference when messages are being received from just one destination. One can either use a CLIENT_ACKNOWLEDGE or Transacted session.

However when using multiple destinations in a session, say receiving message from a queue, then processing it and publishing the process result to another topic in the same session, a transacted session is more suited. So receiving and publishing message will all happen in one transaction. Based on the outcome of the message processing, transaction can either be committed or rolled back.

3
votes

If the session is transacted, the acknowledgeMode is ignored. That's why a new single-argument createSession(int) was added in JMS 2.0 to make it more intuitive. So there's no such thing as "transacted session in auto-acknowledge mode". You either have a transacted or a auto-acknowledged session. Calls to Message.acknowledge() in a transacted session are ignored (it's specified by the JMS API).

So what's the difference? It's not whether you use one or multiple destinations, as multiple places on the internet claim (including the other answer here). It depends on whether the session is consume-only or consume-produce. If it's consume-only (you don't produce any messages), then both modes are equal: calling either Message.acknowledge() or Session.commit() acknowledges all the messages received in the session. Even if received from multiple queues.

Behavior for consume-produce sessions:

  • client-acknowledge: sent messages are committed as soon as the MessageProducer.send() method returns. Client messages are acknowledged all at once when Message.acknowledge() is called. This is not specifically mentioned in the specs, but I think if the broker fails after acking half of the msgs, the client will report an error and only a part of the messages will remain acked. This gives you at-least-once guarantee: if you ack at the end of your process and your program fails mid-way, the output messages will be produced twice.

  • transactional: sent messages are committed atomically together with acknowledging all received messages in the session. No failure on the client or broker side can cause that just a part of the messages is produced or acked. This gives you exactly-once processing guarantee. It's even faster: as claimed here or here, if you produce multiple messages in one transaction, the MessageProducer.send() method will be async and the commit() method will wait for all sends to finish in a batch.