kubernetesjmsmuleactivemq-artemisamq

JMS 2.0 durable subscriptions topic best practice in Kubernetes


We are creating a Mule application which will be running in a container on Kubernetes and will be in a replica set that will be connecting to JMS 2.0 Red Hat AMQ 7 (based on ActiveMQ Artemis).

The pom.xml has been configured to get the jms client:

<dependency>
  <groupId>org.apache.activemq</groupId>
  <artifactId>artemis-jms-client-all</artifactId>
  <version>2.10.1</version>
</dependency>

And the JMS config is configured as:

<jms:config name="JMS_Config" doc:name="JMS Config" doc:id="8621b07d-b203-463e-bbbe-76eb03741a61" >
    <jms:generic-connection specification="JMS_2_0" username="${mq.user}" password="${mq.password}" clientId="${mq.client.id}">
        <reconnection >
            <reconnect-forever frequency="${mq.reconnection.frequency}" />
        </reconnection>
        <jms:connection-factory >
            <jms:jndi-connection-factory connectionFactoryJndiName="ConnectionFactory" >
                <jms:name-resolver-builder jndiInitialContextFactory="org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory" jndiProviderUrl="${mq.brokerurl}"/>
            </jms:jndi-connection-factory>
        </jms:connection-factory>
    </jms:generic-connection>
    <jms:consumer-config>
        <jms:consumer-type >
            <jms:topic-consumer shared="true" durable="true"/>
        </jms:consumer-type>
    </jms:consumer-config>
    <jms:producer-config persistentDelivery="true"/>
</jms:config>

Then in the JMS listener component:

<jms:listener doc:name="EMS JMS Listener" doc:id="318b4f08-daf6-41f4-944b-3ec1420d5c12" config-ref="JMS_Config" destination="${mq.incoming.queue}" ackMode="AUTO" >
    <jms:consumer-type >
        <jms:topic-consumer shared="true" subscriptionName="${mq.sub.name}" durable="true"/>
    </jms:consumer-type>
    <jms:response sendCorrelationId="ALWAYS" />
</jms:listener>

The variables are set as:

mq.client.id=client-id-135a9514-d4d5-4f52-b01c-f6ca34a76b40
mq.sub.name=my-sub
mq.incoming.queue=my-queue

Is this the best way to configure the client? As we have seen errors in the logs when deployed to K8s regarding connections to the AMQ server:

javax.jms.InvalidClientIDException: client-id-135a9514-d4d5-4f52-b01c-f6ca34a76b40 was already set into another connection 

Solution

  • In JMS 2.0 you don't have to set the client identifier when creating a shared durable subscription. However, if you do set the client identifier then it must be unique per connection. For whatever reason (e.g. due to Mule or perhaps K8s) multiple connections are being created and since each connection is using the same client identifier you're receiving the javax.jms.InvalidClientIDException.

    Remove clientId="${mq.client.id}" from your configuration and the javax.jms.InvalidClientIDException should go away.