Saturday, July 23, 2011

Using a HornetQ bridge with JMS order by group

Left this as is for reference, but it doesn't work as designed. See bottom of the post for how to actually get this to work.
Some of our jms processes (several message producers sending to HornetQ jms bridges that push messages to Jboss Messaging queues living in Jboss EAP 5) use message groups for controlling when messages get processed. In this particular environment there are a couple extra steps to make sure it works correctly:

1. Add a new connection factory to the jboss instance where JBM is hosted - edit file deploy/messaging/connection-factories-service.xml and add:

<mbean code="org.jboss.jms.server.connectionfactory.ConnectionFactory"
name="jboss.messaging.connectionfactory:service=GroupedConnectionFactory"
xmbean-dd="xmdesc/ConnectionFactory-xmbean.xml">
<depends optional-attribute-name="ServerPeer">jboss.messaging:service=ServerPeer</depends>
<depends optional-attribute-name="Connector">jboss.messaging:service=Connector,transport=bisocket</depends>
<depends>jboss.messaging:service=PostOffice</depends>

<attribute name="JNDIBindings">
<bindings>
<binding>/GroupedConnectionFactory</binding>
<binding>/GroupedXAConnectionFactory</binding>
<binding>java:/GroupedConnectionFactory</binding>
<binding>java:/GroupedXAConnectionFactory</binding>
</bindings>
</attribute>

<attribute name="EnableOrderingGroup">true</attribute>
</mbean> 

You could of course, edit the existing ConnectionFactory to add the EnableOrderingGroup parameter if you wanted to enable the ordering group for your existing CF, rather than adding a new one and leaving the existing one alone.

2. Change hornetq config (this assumes you already have the other hornetq config done) - edit hornetq-beans.xml, change the target connection factory definition to look like this, making sure you specify the JNDI name of the CF you created in step 1 (GroupedXAConnectionFactory in this case)


<!-- TargetCFF describes the ConnectionFactory used to connect to the target destination --> 
<bean name="TargetCFF" class="org.hornetq.jms.bridge.impl.JNDIConnectionFactoryFactory"> 
<constructor> 
<parameter> 
<inject bean="TargetJNDI" /> 
</parameter> 
<parameter>GroupedXAConnectionFactory</parameter> 
</constructor> 
</bean> 


3. When creating the message to send, make sure you do this:
msg.setStringProperty("JMSXGroupID", myGroupID);

Depending on how you have them configured, you probably will have to restart hornetq and jboss for the changes to take effect. Once completing all these steps, you will be able to send messages through the bridge to the jbm queue and still have the messages grouped/ordered correctly.

Update: This does NOT work since Jboss Messaging doesn't seem to follow the jms spec for message groups. What happens is all the messages that go through this ConnectionFactory end up getting the same group id. I will update the post with how to actually accomplish this.

How to actually do this
1. I think it would work if both messaging servers were JBM, but I'm not sure about the bridging capabilities of jbm, so it may not work for a different reason
2. Have something pull the messages off the hornetq queue where that message grouping works, and submit them to the jbm queues using their setMessageGroup method. This means a lot of extra work and the bridge concept becomes way more complicated, even if it would work.
3. Switch the message provider of the destination (jboss in our case) to hornetq, meaning that both the bridge and the destination have the same message grouping semantics.

We ended up doing #3, and after getting hornetq to work in jboss eap 5 (make sure you read the redhat docs on how to configure this!) it has worked flawlessly.