# JMS Failover With Transaction using Replication Example

This example demonstrates two servers coupled as a live-backup pair for high availability (HA) using replication, and a client connection failing over from live to backup when the live server is crashed.

Failover behavior differs whether the JMS session is transacter or not.

When a transacted JMS session is used, once-and-only once delivery is guaranteed.

- if the failover occurs while there is an in-flight transaction, the transaction will be flagged as rollback only. In that case, the JMS client will need to retry the transaction work.
- if the failover occurs while there is no in-flight transaction, the failover will be transparent to the user.

ActiveMQ Artemis also provides an example for non-transaction failover.

For more information on ActiveMQ Artemis failover and HA, and clustering in general, please see the clustering section of the user manual.

## Example step-by-step

To run the example, simply type `mvn verify -Pexample` from this directory

In this example, the live server is server 1, and the backup server is server 0

The connection will initially be created to server1, server 1 will crash, and the client will carry on seamlessly on server 0, the backup server.

1. Get an initial context for looking up JNDI from server #1.

               initialContext = getContext(1);

2. Look up the JMS resources from JNDI on server #1.

               Queue queue = (Queue)initialContext.lookup("/queue/exampleQueue");
               ConnectionFactory connectionFactory = (ConnectionFactory)initialContext.lookup("/ConnectionFactory");

3. Create a JMS Connection

               connection = connectionFactory.createConnection();

4. Create a JMS transacted Session

               Session session = connection.createSession(true, 0);

5. Start the connection to ensure delivery occurs

               connection.start();

6. Create a JMS MessageProducer

               MessageProducer producer = session.createProducer(queue);

7. Create a JMS MessageConsumer

               MessageConsumer consumer = session.createConsumer(queue);

8. Send half of the messages, kill the live server and send the remaining messages

               sendMessages(session, producer, numMessages, true);

When server #1 crashes, the client automatically detects the failure and automatically fails over from server #1 to server #0 (in your real program you wouldn't need to sleep).

9. As failover occurred during transaction, the session has been marked for rollback only and commit will fail

               try
               {
                  session.commit();
               } catch (TransactionRolledBackException e)
               {
                  System.err.println("transaction has been rolled back: " + e.getMessage());
               }

10. We resend all the messages

               sendMessages(session, producer, numMessages, false);

11. We commit the session successfully: the messages will be all delivered to the activated backup server

               session.commit();

12. We are now transparently reconnected to server #0, the backup server. We consume the messages sent before the crash of the live server, commit the session, and check there are no other message on the queue

            for (int i = 0; i < numMessages; i++)
            {
               TextMessage message0 = (TextMessage)consumer.receive(5000);
               System.out.println("Got message: " + message0.getText());
            }
            session.commit();
            System.out.println("Other message on the server? " + consumer.receive(5000));

13. And finally, always remember to close your resources after use, in a `finally` block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects

               finally
               {
                  if (connection != null)
                  {
                     connection.close();
                  }

                  if (initialContext != null)
                  {
                     initialContext.close();
                  }
               }