Tuesday, October 9, 2012

ActiveMQ Producer Flow Control Send Timeout

ActiveMQ has a feature called Producer Flow Control that throttles back message producers when it detects that broker resources are running low.  In fact, it will block threads sending messages until resources become available.

You can configure the broker to timeout the message send so that it does not block when producer flow control is in effect, but this is a global setting and you cannot configure it per queue.

However, the ActiveMQConnection class has a setSendTimeout() method, but it is not exposed via the JMS connection interface.  There are a couple of ways to handle this.

First, you could simply cast your connection object to an ActiveMQConnection and then call the setSendTimeout method directly.  This works fine if you know for sure your implementation is ActiveMQ and you have access to the ActiveMQ libraries at compile time (in other words, you don't mind having this dependency in your messaging client).

try {
    // Create a ConnectionFactory
    ActiveMQConnectionFactory connectionFactory
        = new ActiveMQConnectionFactory("tcp://localhost:61616");

    QueueConnection connection = connectionFactory.createQueueConnection();
    ((ActiveMQConnection)connection).setSendTimeout(5000);
    ...

A second way to handle this would be to use Java reflection to dynamically invoke the setSendTimeout() method if it is available, like so:

try {
    ...

    QueueConnection connection = connectionFactory.createQueueConnection();

    try {
        Method setSendTimeout = connection.getClass().getMethod(
            "setSendTimeout",
            int.class
        );
        if (null != setSendTimeout) {
            setSendTimeout.invoke(connection, 5000);
        }
    } catch (Exception e) {
        System.out.println("could not invoke the setSendTimeoutMethod"); 
    }
    ...

With this approach, you can configure send timeouts per connection and you can be somewhat JMS provider agnostic in your client. Keep in mind that if you use a container to provide your JMS connection factory the connections you get back may not be ActiveMQ connections, but rather proxy objects that wrap an ActiveMQ connection.