JMS Transactions, Delivery Reliability and Real World Use Case

What are JMS Transactions

The most reliable way to produce a message is to send a PERSISTENT message within a transaction. JMS messages are PERSISTENT by default. A transaction is a unit of work into which you can group a series of operations, such as message sends and receives, so that the operations either all succeed or all fail. For details, see Specifying Message Persistence and Using JMS API Local Transactions.

The most reliable way to consume a message is to do so within a transaction, either from a queue or from a durable subscription to a topic. For details, see Creating Temporary Destinations, Creating Durable Subscriptions, and Using JMS API Local Transactions.

For other applications, a lower level of reliability can reduce overhead and improve performance. If your application does not use transactions, it can use one of these acknowledgement modes: auto, duplicates okay, and client.

If your application uses transactions, it can choose from these transaction options: transacted session, MDB with container-managed transaction demarcation (CMTD), and MDB with bean-managed transaction demarcation (BMTD).

Transaction options:

  1. Transacted session: An application can participate in a transaction by creating a transacted session (or local transaction). The application completely controls the message delivery by either committing or rolling back the session.
  2. Message-driven beans with CMTD: An MDB can participate in a container transaction by specifying CMTD in the XML deployment descriptor. The transaction commits upon successful message processing or the application can explicitly roll it back.
  3. Message-driven beans with BMTD: An MDB can choose not to participate in a container transaction by specifying BMTD in the XML deployment descriptor. The MDB programmer has to design and code programmatic transactions.

One of important things to note here is that if you enable "JMS Transactions", acknowledge modes does not have any effect. 

JMS support
  1. Transactional send
  2. Transactional receive
  3. Transacted producers and transacted consumers can be grouped together in a single transaction if they are created from the same session object.

Creating a JMS Transaction 

Enabling a JMS transacted session happens as part of creating a Session object, as shown below.
// pub/sub connection creates a transacted TopicSession
javax.jms.TopicSession session=connect.createTopicSession(true,Session.AUTO_ACKNOWLEDGE);
// p2p connection creates a transacted QueueSession
javax.jms.QueueSession = 

The first parameter of createTopicSession() or createQueueSession() method is a Boolean indicating whether this is a transacted session. That is all we need to create a transactional session. There is no explicit begin() method. When a session is transacted, all messages sent or received using that session are automatically grouped in a transaction. The transaction remains open until either a session.rollback() or a session.commit() happens, at which point a new transaction is started. An additional Session method, isTransacted(), returns a Boolean true or false indicating whether the current session is transactional.

Distributed Transactions 

Having all producers and all consumers participate in one global transaction would defeat the purpose of using a loosely coupled asynchronous messaging environment.

Sometimes it's necessary to coordinate the send or receipt of a JMS transaction with the update of another non-JMS resource, like a database or an EJB entity bean. This typically involves an underlying transaction manager that takes care of coordinating the prepare, commit, or rollback of each resource participating in the transaction. JMS provides JTA transaction interfaces for accomplishing this.

JMS providers that implement the JTA XA APIs can participate as a resource in a two-phase commit. The JMS specification provides XA versions of the following JMS objects : XAConnectionFactory, XAQueueConnection, XAQueueConnectionFactory, XAQueueSession, XASession, XATopicConnection, XATopicConnectionFactory, and XATopicSesion.

What JMS Transactions can do?

JMS transactions are very important when we come to message delivery reliability. Even though non-transactional JMS can provide a certain degree of message delivery reliability, in practical world even message acknowledgements can be lost inside a network.
Distributed transactions are important when you want to do a JMS transaction plus a Database transaction in a single transaction. A good article which discuss these can be found here.

Real World Use Case

In real world messaging systems there can be bulk message processing part triggered around time that there is a less number of "user inputs" to the system (maybe at mid-night :D).

  1. Get  user records from database collected within the day.
  2.  Process them chunk by chunk.
  3. Write processed data to a database.
  4. There cannot be message duplication as one record should be processed only once and written to the database. Otherwise it would seem user has requested same thing twice (or many times).
  5. There cannot be a message lost because what you process is the user requests. If a lost happens it is analogous to that user has not made any request. 

In such a situation we need a JMS broker in the middle and also JMS transactions to handle message rollback if the database write or processing failure happened. To make the system more robust we need to use "Broker Failover" allowing the system to use a backup JMS broker if current broker is crashed or unreachable.

We will see how to Setup WSO2 ESB for a situation like above using WSO2 Message Broker as the JMS provider. This is discussed in a separate post titled "Get JMS Local Transactions To Work With WSO2 ESB+WSO2 MEssage Broker Setup".

Hasitha Hiranya

No comments:

Post a Comment