<html>
<head>
<title>ActiveMQ Application-Layer Failover Example</title>
<link rel="stylesheet" type="text/css" href="../common/common.css" />
<link rel="stylesheet" type="text/css" href="../common/prettify.css" />
<script type="text/javascript" src="../common/prettify.js"></script>
</head>
<body onload="prettyPrint()">
<h1>Application-Layer Failover Example</h1>
<p>ActiveMQ implements fully transparent <b>automatic</b> failover of connections from a live node to a backup node which requires
no special coding. This is described in a different example and requires server replication.</p>
<p>However, ActiveMQ also supports <b>Application-Layer</b> failover which is useful in the case where replication is not enabled.</p>
<p>With Application-Layer failover, it's up to the application to register a JMS ExceptionListener with ActiveMQ.
This listener will then be called by ActiveMQ in the event that connection failure is detected.</p>
<p>User code in the ExceptionListener can then recreate any JMS Connection, Session, etc on another node and the application
can continue.</p>
<p>Application-Layer failover is an alternative approach to High Availabilty (HA).</p>
<p>Application-Layer failover differs from automatic failover in that some client side coding is required in order
to implement this. Also, with Application-Layer failover, since the old Session object dies and a new is created, any uncommitted
work in the old Session will be lost, and any unacknowledged messages might be redelivered.</p>
<p>For more information on ActiveMQ failover and HA, and clustering in general, please see the clustering
section of the user manual.</p>
<h2>Example step-by-step</h2>
<p><i>To run the example, simply type <code>mvn verify</code> from this directory</i></p>
<p>In this example, the live server is server 1, which will failover onto server 0.</p>
<p>The connection will initially be created to server1, server 1 will crash, and the client will carry on
on server 0, the new server. With Application-Layer failover the node that is failed over onto, does not need to
be specially configured as a backup server, it can be any node.</p>
<ol>
<li> We create our JMS Connection, Session, MessageProducer and MessageConsumer on server 1</li>
<pre class="prettyprint">
<code>createJMSObjects(1);</code>
</pre>
<li>We set a JMS ExceptionListener on the connection. On failure this will be called and the connection,
session, etc. will be manually recreated on the backup node.</li>
<pre class="prettyprint">
<code>connection.setExceptionListener(new ExampleListener());</code>
</pre>
<li>We send some messages to server 1, the live server.</li>
<pre class="prettyprint">
<code>
final int numMessages = 10;
for (int i = 0; i < numMessages; i++)
{
TextMessage message = session.createTextMessage("This is text message " + i);
producer.send(message);
System.out.println("Sent message: " + message.getText());
}
</code>
</pre>
<li>We consume those messages on server 1.</li>
<pre class="prettyprint">
<code>
for (int i = 0; i < numMessages; i++)
{
TextMessage message0 = (TextMessage)consumer.receive(5000);
System.out.println("Got message: " + message0.getText());
}
</code>
</pre>
<li>We now cause server 1, the live server to crash. After a little while the connection's
ExceptionListener will register the failure and reconnection will occur.</li>
<pre class="prettyprint">
<code>killServer(1);</code>
</pre>
<li>The connection's ExceptionListener gets called, and we lookup the JMS objects and
recreate the connection, session, etc on the other node 0.</li>
<pre class="prettyprint">
<code>
private class ExampleListener implements ExceptionListener
{
public void onException(JMSException exception)
{
try
{
// Close the old resources
closeResources();
// Create new JMS objects on the backup server
createJMSObjects(0);
failoverLatch.countDown();
}
catch (Exception e)
{
System.err.println("Failed to handle failover");
e.printStackTrace();
}
}
}
</code>
</pre>
<li>We are now connected to the other node. We now send some more messages.</li>
<pre class="prettyprint">
<code>
for (int i = numMessages; i < numMessages * 2; i++)
{
TextMessage message = session.createTextMessage("This is text message " + i);
producer.send(message);
System.out.println("Sent message: " + message.getText());
}
</code>
</pre>
<li>And consume them.</li>
<pre class="prettyprint">
<code>
for (int i = 0; i < numMessages; i++)
{
TextMessage message0 = (TextMessage)consumer.receive(5000);
System.out.println("Got message: " + message0.getText());
}
</code>
</pre>
<li>And finally (no pun intended), <b>always</b> remember to close your resources after use, in a <code>finally</code> block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects</li>
<pre class="prettyprint">
<code>
finally
{
closeResources();
}
</code>
</pre>
</ol>
</body>
</html>