Book Image

Instant Apache ActiveMQ Messaging Application Development How-to

By : Timothy A. Bish
Book Image

Instant Apache ActiveMQ Messaging Application Development How-to

By: Timothy A. Bish

Overview of this book

Apache ActiveMQ is a powerful and popular open source messaging and Integration Patterns server. ActiveMQ is a fully JMS 1.1 compliant Message Broker and supports many advanced features beyond the JMS specification.Instant ActiveMQ Application Development How-to shows you how to get started with the ActiveMQ Message Broker. You will learn how to develop message-based applications using ActiveMQ and the JMS specification. In this book you will learn all the basic skills you need to start writing Java Messaging applications with a firm grounding in the more advanced features of ActiveMQ, giving you the tools to continue to master application development using ActiveMQ. Starting by applying the messaging features of the JMS specification to write basic messaging applications, you will develop a basic JMS application using topics and queues to broadcast events as well as perform Request and Response operations over the JMS. Once you have mastered the simple tasks you will move onto using the advanced features in ActiveMQ to supercharge your messaging applications. You will get to grips with ActiveMQ's scheduler to delay messages. You will also learn how to leverage ActiveMQ's fault-tolerant capabilities to create robust client applications.
Table of Contents (7 chapters)

Using Failover transport (Advanced)


In this recipe we look at how we can create more robust JMS applications by making use of ActiveMQ's Failover transport to automatically reconnect a client to a broker in case of a connection failure. We will also discuss some general error-handling tips when using JMS in our applications.

Getting ready

For this recipe we will use two examples; the first is failover-producer and the second is failover-consumer that demonstrate how a lost connection doesn't have to affect our client applications.

How to do it...

To run the sample for this recipe, you will need to perform the following steps:

  1. Open a terminal and start a broker.

  2. Open a second terminal, change the path to the directory where failover-consumer is located, and run it by typing mvn compile exec:java.

  3. Open a third terminal and change the path to point to the directory where failover-producer is located and run it by typing mvn compile exec:java.

  4. While the producer and consumer applications are running, shut down the running broker instance and restart it.

In the terminal where you started the consumer example, you will see output similar to the following snippet, indicating that the application is running:

Starting example Failover Consumer now...
Failover Consumer received Message #1
Failover Consumer received Message #2
Failover Consumer received Message #3
Failover Consumer received Message #4
Failover Consumer received Message #5
Failover Consumer received Message #6
2013-03-06 14:15:23,731 [0.1:61616@59602] - WARN  FailoverTransport              - Transport (tcp://127.0.0.1:61616) failed, reason:  java.io.EOFException, attempting to automatically reconnect
Failover Consumer received Message #7
Failover Consumer received Message #8

In the terminal windows where you started the producer example you will see output like following indicating that the application is running.

Starting example Failover Producer now...
Failover Producer sent Message #1
Failover Producer sent Message #2
Failover Producer sent Message #3
Failover Producer sent Message #4
Failover Producer sent Message #5
Failover Producer sent Message #6
2013-03-06 14:15:23,733 [0.1:61616@59606] - WARN  FailoverTransport- Transport (tcp://127.0.0.1:61616) failed, reason:  java.io.EOFException, attempting to automatically reconnect
Failover Producer sent Message #7

You can start and stop the broker as many times as you wish during the run of the examples; they will each detect and recover from the connection loss. The producer will finish after it has sent 1000 messages successfully to the queue.

How it works...

Up to this point in the book, we haven't really talked much about what happens when a broker fails while a client is producing or consuming messages. JMS, on its own, doesn't specify any sort of failover or loss of connection-handling behavior for the JMS provider. If your client connects to ActiveMQ Broker using the standard TCP-based transport protocol we've been using in our examples so far, when the broker fails, the client connection breaks and an exception will be generated as soon as the client notices that the connection is gone.

There are two ways your client can get notified of a connection error. The first is by an exception being thrown from a method call such as a send() operation, and the second is from an asynchronous exception listener registered on the Connection object. The asynchronous exception interface is shown here:

class ExceptionListener {
    void onException(JMSException ex);
}

In order to receive the asynchronous exceptions, your code implements the ExceptionListener interface and does something to react to the error. Reacting to the error is where things get complicated. There are a number of exception types defined in the JMS API. In spite of this, when an error occurs but your connection is still usable, it's tricky to tell whether you need to shut everything down and rebuild the JMS resources from scratch. Doing so is usually not a trivial bit of work inside your application. Fortunately, ActiveMQ provides us with an elegant solution to dealing with connection failures in our client applications.

ActiveMQ provides a Transport protocol known as Failover transport that can do the work of dealing with connection problems in our applications, leaving us to focus on our business logic and not worry about how we deal with every failure case. We used Failover transport in the examples for the recipe so that you could start and stop your broker as much as you wanted without the examples failing before they had sent and received all their messages.

Using Failover transport in our examples, or any of the other examples in this book, requires only one change to the way we we've implemented our code so far. That change is in the connection URI we passed to our ConnectionFactory instance; here's what the URI looks like in this recipe's examples:

failover:tcp://localhost:61616

That's it, we just added one little word, "failover", to the connection URI and the client becomes fault tolerant. That's pretty great right?

Failover transport isn't limited to just keeping our client connected to only one broker. We can specify the address of several brokers on our client's connection URI and Failover transport will work its way through them as brokers fail, allowing us to ensure that our client can quickly recover when it loses contact with the connected broker. If we knew that there were two brokers on our network and we wanted our client to failover to another when needed, we could use a URI similar to the following one:

failover:(tcp://host1:61616,tcp://host2:61616)

You can add an entry for every broker on your network in this manner, and the client will connect to the next available broker whenever one goes down. By default, the transport selects a random host from the set of available hosts each time it tries to connect. You can alter the URI to make this process non-random with the following change.

failover:(tcp://host1:61616,tcp://host2:61616)?randomize=false

There's more...

When a client's connection is down and Failover transport is working to reconnect to another broker, any call that your client makes that involves sending information to the broker will be blocked until the connection is restored. It's possible to monitor what Failover transport is doing in your application by using the TransportListener interface provided by the ActiveMQ client API.

The TransportListener interface provides methods for being notified of connection interruption as well as resumption of connection. You can also listen in on the exceptions that are thrown and other commands sent from the broker. You create and add a TransportListener interface to your connection with the following code:

Class MyTransportListener implements TransportListener {
    public void onCommand(Object command) {}
    public void onException(IOException error) {
 
    public void transportInterupted() {
        // app logic
    }
 
    public void transportResumed() {
        // app logic
    }
}

MyTransportListener listener = new MyTransportListener();
((ActiveMQConnection) connection).addTransportListener(listener);

Implementing a TransportListener interface is a good way to add logging to your application that reports on the connection state of your client as well as logging exceptions.

Using Failover transport in a broker cluster

We said earlier that when you configure your client connection URI for failover, you can specify the address of several different brokers that the client can try connecting to when things go wrong. This is a great feature, but imagine that your client operates in a large cluster of ActiveMQ Brokers where broker instances can be added or removed at any time. It would be quite cumbersome to stop all the running clients, update their connection URIs, and restart them every time the broker cluster changes. Fortunately, there's a solution for this problem.

By enabling the update cluster clients option in your ActiveMQ Broker-side configuration file, you can have the broker send information to the clients that keeps their Failover transports updated on the brokers currently running in a cluster. Enabling this feature is simple; you just update your configuration to look like the following snippet:

<broker>
  ...
  <transportConnectors>
    <transportConnector name="openwire" uri="tcp://0.0.0.0:61616" updateClusterClients="true" updateClusterFilter="*A*,*B*" />
  </<transportConnectors>
  ...
</broker>

Now, in your client code, you only need to specify the address of the first broker in your cluster and the client will be updated as other brokers are added.

It's also possible to have the brokers in a cluster rebalance the connected clients to more evenly distribute the load across the cluster using this update cluster clients feature. You can read more about this as well as other options available for configuring your failover-enabled clients on the ActiveMQ site, http://activemq.apache.org/failover-transport-reference.html.

Complete Failover transport configuration reference

Failover transport has a number of configuration options that allow your application to specify exactly how it wants the transport to behave. For instance, you can specify that the transport only attempts to connect to the broker a set number of times before giving up. The complete reference for Failover transport options can be found on the ActiveMQ website, http://activemq.apache.org/failover-transport-reference.html.