Search code examples
jmsactivemq-classicwildfly-10activemq-artemis

JMS Bridge Between WildFly 10 Artemis and ActiveMQ 5.14 (ONCE_AND_ONLY_ONCE Quality of Service)


I'm trying to set up a JMS Bridge between Artemis (Running in WildFly 10) and ActiveMQ 5.14

In general the process seems to work smoothly, but unfortunately I'm getting stuck on the XA configuration that is necessary to get ONCE_AND_ONLY_ONCE QoS to work.

Although messages do arrive on the ActiveMQ side, I get the following error in the WildFly log:

11:25:57,920 WARN  [org.apache.activemq.artemis.jms.bridge] (Thread-97) AMQ342009: JMS Bridge failed to send + acknowledge batch, closing JMS objects: javax.jms.IllegalStateException: Not a transacted session
at org.apache.activemq.ActiveMQSession.commit(ActiveMQSession.java:577)
at org.apache.activemq.ra.ManagedSessionProxy.commit(ManagedSessionProxy.java:108)
at org.apache.activemq.artemis.jms.bridge.impl.JMSBridgeImpl.sendBatchNonTransacted(JMSBridgeImpl.java:1291)
at org.apache.activemq.artemis.jms.bridge.impl.JMSBridgeImpl.sendBatch(JMSBridgeImpl.java:1251)
at org.apache.activemq.artemis.jms.bridge.impl.JMSBridgeImpl.access$1500(JMSBridgeImpl.java:75)
at org.apache.activemq.artemis.jms.bridge.impl.JMSBridgeImpl$BatchTimeChecker.run(JMSBridgeImpl.java:1794)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)

My problem is similar to this one (Wildfly 10 ONCE_AND_ONLY_ONCE JMS bridge ) but unfortunately the solution doesn't totally apply to my situation, because my target is ActiveMQ 5.14.

From all the posts I've read it seems clear that I should ensure that the connection factories for both sides of the bridge should be configured for XA Support. On the Artemis side this seems simple enough: Simply add factory-type="XA_GENERIC" to the definition. However, I'm not able to figure out how to do this on the ActiveMQ side.

Here's the snippet from my standalone-full.xml that specifies my messaging subsystem:

    <subsystem xmlns="urn:jboss:domain:messaging-activemq:1.0">
        <server name="default">
            <security-setting name="#">
                <role name="guest" delete-non-durable-queue="true" create-non-durable-queue="true" consume="true" send="true"/>
            </security-setting>
            <address-setting name="#" message-counter-history-day-limit="10" page-size-bytes="2097152" max-size-bytes="10485760" expiry-address="jms.queue.ExpiryQueue" dead-letter-address="jms.queue.DLQ"/>
            <http-connector name="http-connector" endpoint="http-acceptor" socket-binding="http"/>
            <http-connector name="http-connector-throughput" endpoint="http-acceptor-throughput" socket-binding="http">
                <param name="batch-delay" value="50"/>
            </http-connector>
            <in-vm-connector name="in-vm" server-id="0"/>
            <http-acceptor name="http-acceptor" http-listener="default"/>
            <http-acceptor name="http-acceptor-throughput" http-listener="default">
                <param name="batch-delay" value="50"/>
                <param name="direct-deliver" value="false"/>
            </http-acceptor>
            <in-vm-acceptor name="in-vm" server-id="0"/>
            <jms-queue name="ExpiryQueue" entries="java:/jms/queue/ExpiryQueue"/>
            <jms-queue name="DLQ" entries="java:/jms/queue/DLQ"/>
            <jms-queue name="NonBridgedTestQueue" entries="java:jboss/exported/jms/queue/nonBridgedTestQueue"/>
            <jms-queue name="BridgedTestQueue" entries="java:jboss/exported/jms/queue/bridgedTestQueue"/>
            <connection-factory name="InVmConnectionFactory" entries="java:/ConnectionFactory" connectors="in-vm"/>
            <connection-factory name="RemoteConnectionFactory" entries="java:jboss/exported/jms/RemoteConnectionFactory" connectors="http-connector"/>
            <connection-factory name="InVmXAConnectionFactory" factory-type="XA_GENERIC" entries="java:/XAConnectionFactory" connectors="in-vm"/>               
            <pooled-connection-factory name="activemq-ra" transaction="xa" entries="java:/JmsXA java:jboss/DefaultJMSConnectionFactory" connectors="in-vm"/>
        </server>
        <jms-bridge name="simple-jms-bridge" add-messageID-in-header="true" max-batch-time="100" max-batch-size="10" max-retries="5" failure-retry-interval="10000" quality-of-service="ONCE_AND_ONLY_ONCE">
            <source destination="jboss/exported/jms/queue/bridgedTestQueue" connection-factory="java:/XAConnectionFactory"/>
            <target destination="jboss/activemq/queue/bridgedTestQueue" connection-factory="AMQConnectionFactory"/>
        </jms-bridge>
    </subsystem>

For the ActiveMQ definition I've used a Resource Adapter, defined as follows:

    <subsystem xmlns="urn:jboss:domain:resource-adapters:4.0">
        <resource-adapters>
            <resource-adapter id="activemq">
                <archive>activemq-rar-5.14.0.rar</archive>
                <transaction-support>XATransaction</transaction-support>
                <config-property name="ServerUrl">tcp://localhost:61616?jms.rmIdFromConnectionId=true</config-property>
                <config-property name="UserName">admin</config-property>
                <config-property name="UseInboundSession">false</config-property>
                <config-property name="Password">admin</config-property>
                <connection-definitions>
                    <connection-definition class-name="org.apache.activemq.ra.ActiveMQManagedConnectionFactory" jndi-name="java:/AMQConnectionFactory" enabled="true" pool-name="AMQConnectionFactory">
                        <xa-pool>
                            <min-pool-size>1</min-pool-size>
                            <max-pool-size>20</max-pool-size>
                            <prefill>false</prefill>
                            <is-same-rm-override>false</is-same-rm-override>
                        </xa-pool>
                    </connection-definition>
                </connection-definitions>
                <admin-objects>
                    <admin-object class-name="org.apache.activemq.command.ActiveMQTopic" jndi-name="java:jboss/activemq/topic/TestTopic" use-java-context="true" pool-name="TestTopic">
                        <config-property name="PhysicalName">
                            activemq/topic/TestTopic
                        </config-property>
                    </admin-object>
                    <admin-object class-name="org.apache.activemq.command.ActiveMQQueue" jndi-name="java:jboss/activemq/queue/TestQueue" use-java-context="true" pool-name="TestQueue">
                        <config-property name="PhysicalName">
                            activemq/queue/TestQueue
                        </config-property>
                    </admin-object>
                    <admin-object class-name="org.apache.activemq.command.ActiveMQQueue" jndi-name="java:jboss/activemq/queue/bridgedTestQueue" use-java-context="true" pool-name="BridgedTestQueue">
                        <config-property name="PhysicalName">
                            activemq/queue/bridgedTestQueue
                        </config-property>
                    </admin-object>
                </admin-objects>
            </resource-adapter>
        </resource-adapters>
    </subsystem>

Some pointers in the right direction will be appreciated

Greg


Solution

  • After posting this question I tried something that seems to have worked. Would still be interested to hear if this is the correct approach though.

    When looking at the ra.xml file in the resource adapter I noticed that it offers an additional connection factory as an admin object. So I added the following to the Resource Adapter definition in standalone-full.xml:

                        <admin-object class-name="org.apache.activemq.ActiveMQXAConnectionFactory" jndi-name="java:jboss/activemq/activeMQXAConnectionFactory" use-java-context="true">
                            <config-property name="brokerURL">
                                tcp://localhost:61616?jms.rmIdFromConnectionId=true
                            </config-property>
                        </admin-object>
    

    Using this Connection Factory I then updated the JMS Bridge as follows:

            <jms-bridge name="simple-jms-bridge" add-messageID-in-header="true" max-batch-time="100" max-batch-size="10" max-retries="5" failure-retry-interval="10000" quality-of-service="ONCE_AND_ONLY_ONCE">
                <source destination="jboss/exported/jms/queue/bridgedTestQueue" connection-factory="java:/XAConnectionFactory"/>
                <target destination="jboss/activemq/queue/bridgedTestQueue" connection-factory="java:jboss/activemq/activeMQXAConnectionFactory"/>
            </jms-bridge>
    

    Now all seems to work well. Messages arrive on the ActiveMQ side and I'm not getting any issues in the WildFly log. Whoopwhoop