Resolving Durable Duplicate Client ID Issues

Once I completed the previous blog post: Spring and WebLogic Durable Subscriber, the configurations were deployed to a multiple domain cluster (with some Managed Servers running on a separate physical machines). Errors started to occur within the cluster based on the use of the SingleConnectionFactory configuration. What appeared to be happening was when the subscribe war was deployed out to WebLogic Server, the 1st Managed Server started and created a durable session with the configured clientId. The problem was when the war started on the 2nd Managed Server, it attempted to create a durable session with that same configured clientId and we started receiving errors such as this:

[JMSClientExceptions:055083]Cannot set clientid to sampleSubscribeService. The client ID is already set to sampleSubscribeService
2012-12-28 12:40:12,604 THREAD:[143] WARN ID:[] org.springframework.jms.listener.DefaultMessageListenerContainer – Could not refresh JMS Connection for destination ‘jmsServer1@com/foo/dest/SampleTopic’ – retrying in 3600000 ms. Cause: [JMSClientExceptions:055083]Cannot set clientid to sampleSubscribeService. The client ID is already set to sampleSubscribeService

The following configuration existed (as shown in the other blog) for the subscribe service:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<bean id="sampleDurableTopicConnectionFactory"
    class="org.springframework.jms.connection.SingleConnectionFactory"
    p:targetConnectionFactory-ref="sampleMessagingConnectionFactory"
    p:clientId="sampleSubscribeService"/>

<bean id="sampleSubscribeServiceListenerContainer"  
    class="org.springframework.jms.listener.DefaultMessageListenerContainer"
    p:connectionFactory-ref="sampleDurableTopicConnectionFactory"
    p:destinationName="jmsServer1@com/foo/dest/SampleTopic"
    p:destinationResolver-ref="sampleDestinationResolver"
    p:messageListener-ref="sampleSubscribeServiceMessageListener"
    p:pubSubDomain="true"
    p:subscriptionDurable="true"
    p:durableSubscriptionName="sampleSubscribeService"
    p:transactionManager-ref="GlobalDataTransactionManager"/>

This included the configuration for the WebLogic Server ConnectionFactory:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<connection-factory name="SampleConnectionFactory">
    <default-targeting-enabled>true</default-targeting-enabled>
    <jndi-name>com/foo/SampleConnectionFactory</jndi-name>
    <client-params>
        <client-id-policy>Restricted</client-id-policy>
        <subscription-sharing-policy>Exclusive</subscription-sharing-policy>
        <messages-maximum>15</messages-maximum>
    </client-params>
    <transaction-params>
        <xa-connection-factory-enabled>true</xa-connection-factory-enabled>
    </transaction-params>
    <security-params>
        <attach-jmsx-user-id>false</attach-jmsx-user-id>
    </security-params>
</connection-factory>

So in order to resolve this issue, there were a few necessary changes. The first change dealt with moving the clientId configuration out of Spring (which required the SingleConnectionFactory) and moving the clientId configuration into the WebLogic Server ConnectionFactory. It also required the modification of how the ConnectionFactory was configured with clientId properties. The configuration needed to change to add the clientId, allow the clientId to be duplicated, and change the subscription sharing policy. The JMS resource configuration changed the the following.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<connection-factory name="SampleConnectionFactory">
    <default-targeting-enabled>true</default-targeting-enabled>
    <jndi-name>com/foo/SampleConnectionFactory</jndi-name>
    <client-params>
                <client-id>sampleClientId</client-id>
            <client-id-policy>Unrestricted</client-id-policy>
            <subscription-sharing-policy>Sharable</subscription-sharing-policy>
                <messages-maximum>15</messages-maximum>
    </client-params>
    <transaction-params>
        <xa-connection-factory-enabled>true</xa-connection-factory-enabled>
    </transaction-params>
    <security-params>
        <attach-jmsx-user-id>false</attach-jmsx-user-id>
    </security-params>
</connection-factory>

Also changed the forwarding-policy for Topics from Replicated to Partitioned.

There was one last item that needed to be configured because of the use of UDTs in WebLogic Server as opposed to default Topics. UDTs do not inherently support durable subscribes unless the WAR subscribes to an individual member of the cluster. This requires the WAR to subscribe to a specific jmsServer instance. The problem is when there is a multiple machine cluster (jmsServer1, jmsServer2, etc) and a WAR is deployed to the cluster, how do we specify the individual jmsServer instance in the Spring configuration. This approach would be solved by supplying a system level property in the domain scripts of WebLogic Server (there is a start script per Managed Server) and so each Managed Server script would export a system property of the name of the jmsServer.

1
2
3
4
5
JMS_SERVER_NAME=jmsServer1
export JMS_SERVER_NAME

EXTRA_JAVA_PROPERTIES="$ $ $ $ -DjmsServer.Name=$ -Dweblogic.debug.DebugDeploy -Dweblogic.debug.MasterDeployer -Dweblogic.debug.ApplicationContainer -Dcom.sun.management.jmxremote.authenticate=false"
export EXTRA_JAVA_PROPERTIES

Then, the Spring configuration for the DefaultMessageListenerContainer could simply inject that system property into the JMS destinationName property, as such:

1
2
3
4
5
6
7
8
9
10
<bean id="sampleSubscribeServiceListenerContainer"  
    class="org.springframework.jms.listener.DefaultMessageListenerContainer"
    p:connectionFactory-ref="sampleMessagingConnectionFactory"
    p:destinationName="${jmsServer.Name:jmsServer1}@com/foo/dest/SampleTopic"
    p:destinationResolver-ref="sampleDestinationResolver"
    p:messageListener-ref="sampleSubscribeServiceMessageListener"
    p:pubSubDomain="true"
    p:subscriptionDurable="true"
    p:durableSubscriptionName="sampleSubscribeService"
    p:transactionManager-ref="GlobalDataTransactionManager"/>

This resolved the duplicate clientId issues, allowed the WARs to work in a cluster against UDTs, and also correctly allowed the UDTs to load balance incoming messages to each instance in the cluster.

maxim peptide coupon

Share and Enjoy