Use same JMS ClientID for multiple destinations/topics - jms

I'm working on an new application that subscribes to two topics on a JBoss 4 and processes incoming messages. Actually I'm using two DefaultMessageListenerContainer with durable subscriptions for the connection.
When I use the same ClientID for the durable Subscription the Container fails with the error:
2021-07-02T10:28:05.487+0200 [DefaultMessageListenerContainer-1] ERROR org.springframework.jms.listener.DefaultMessageListenerContainer - Could not refresh JMS Connection for destination 'TOPIC.providerDurableTopic' - retrying using FixedBackOff{interval=5000, currentAttempts=0, maxAttempts=unlimited}. Cause: This client id 'ka03.9971.mueller.de' is already registered!
Are there any possibilities two use the same clientId for two different destinations. Is there maybe any other ListenerContainer that can handle multiple destinations with one container instance?
The reason we try to use the same clientId is because we try to replace an old application with it subscriptions. This old application connected to the topics within one JMS transaction and was able to use the same client id.

I guess one possible solution is to use the SingleConnectionFactory and set the clientId on it. So only one Connection will be used for both Topics

The JMS 1.1 specification explicitly prohibits multiple connections with the same Client ID. I see three potential solutions to your problem:
Each message listener can use a connection with a unique Client ID.
Both message listeners can use the same connection.
Upgrade to a JMS 2 broker (e.g. ActiveMQ Artemis). JMS 2 relaxed the requirements for durable subscriptions and Client ID is no longer strictly required.

Related

Loading balancing consumers on topics on ActiveMQ Artemis

I am using ActiveMQ Artemis 2.10 and JMS Client 1.1 client.
If I used the multicast routing type on my address and needed durable subscriptions, how do I achieve load balancing on the consumer side?
With ActiveMQ 5 it would be virtual destinations.
It is unclear how a consumer side load-balancing could be achieved with ActiveMQ Artemis 7.2 and JMS Client 1.1 client when consuming off durable subscriptions on a topic.
In the example above:
Each of the consumers would set the clientId (client123 and client456) in the example, but this would mean there can be only one instance of client123 consuming from client123.topic.foo.
My current understanding is that ActiveMQ Artemis 2.10 and JMS Client 1.1 client implies you cannot have load balancing on topics, would that be correct?
The only option seems to be ActiveMQ Artemis 2.10 and JMS Client 2.0 which allows you to create Shared Durable subscriptions, would that be correct?
Is there a 3rd option?
My current understanding is that Active MQ Artemis 7.2 and JMS Client 1.1 client implies you cannot have load balancing on topics, would that be correct?
No.
The only option seems to be Active MQ Artemis 7.2 and JMS Client 2.0 which allows you to create Shared Durable subscriptions, would that be correct?
No.
Is there a 3rd option?
Yes. You can use the durable subscription's fully qualified queue name with a JMS consumer. As noted in the JMS-to-core mapping document, a JMS topic is mapped to a core address and a subscription on that JMS topic is mapped to a core queue on the core address. In the case of a durable JMS subscription the name of that queue follows the pattern "<clientID>.<subscriptionName>". Here's some example code to demonstrate:
ConnectionFactory cf = new ActiveMQConnectionFactory("tcp://127.0.0.1:61616");
Connection connection1 = cf.createConnection();
connection1.setClientID("myClientID");
Session session1 = connection1.createSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = new ActiveMQTopic("myTopic");
MessageConsumer consumer1 = session1.createDurableSubscriber(topic, "mySubscriptionName");
Connection connection2 = cf.createConnection();
Session session2 = connection2.createSession();
Destination destination = new ActiveMQQueue("myTopic::myClientID.mySubscriptionName");
MessageConsumer consumer2 = session2.createConsumer(destination);
// Send 2 messages
MessageProducer producer = session1.createProducer(topic);
producer.send(session1.createMessage());
producer.send(session1.createMessage());
producer.close();
// Receive the first message with the first consumer
connection1.start();
Message message1 = consumer1.receive();
consumer1.close();
// Receive the second message with the second consumer
connection2.start();
Message message2 = consumer2.receive();
consumer2.close();
To say it another way...
Since JMS 1.1 doesn't explicitly allow shared durable subscriptions then you can't horizontally scale applications using createDurableSubscriber on the same topic with the same client identifier and subscription name. However, you can scale horizontally if one application uses createDurableSubscriber and all the others simply consume directly from the underlying subscription queue using its "fully qualified queue name" (which is derived from the client identifier and subscription name used when it was first created using createDurableSubscriber).

Spring JMS 4.3.2 + Jboss EAP 6.4.8 + Webmethods Jms Broker 8.2 + Durable shared topic subscription

I'm trying to subscribe to a topic using durable and shared enabled, so that multiple instance can be connected to a topic to increase the scalability.
However, only the first instance getting connected without any errors, the second instance message listener keeps throwing the below error messages. I checked with my Webmethods counterpart and he found that the client state was disabled and that's why second listener was not able to connect using the same subscription name.
Can someone throw light on this issue please.
18:14:15,050 WARN
[org.springframework.jms.listener.DefaultMessageListenerContainer]
(DefaultMessageListenerContainer-145) Setup of JMS message listener
invoker failed for destination 'topicName' - trying to recover. Cause:
[BRM.10.2209] JMS: Durable subscription
"connectionFactory##subscriptionName" is in use.
The message
JMS: Durable subscription "connectionFactory##subscriptionName" is in use.
typically hints at a misconfiguration of your Topic on Broker. Please check (with MWS) that the Topic really has "Shared State=true“:
Then make sure your Connection Factory has a „Connection Factory Client ID“ set:
And finally you should set the following JVM setting:
-Dcom.webmethods.jms.clientIDSharing=true

More than one JMS ConnectionFactory

I am new to JMS and currently developing a simple Chat application explained in Oreilly 'Java Message service'. I've configured a TopicConnectionFactory in ActiveMQ that receives chat messages from TopicPublishers and dispatch that to TopicSubscribers.
My question is 'why do we need to create more than one TopicConnectionFactory' in any JMS application? Since Connectionfactory instances are not tied up with a Topic/Queue, why can't we use one instance of ConnectionFactory for creating connections to all the Topics (or Queues) configured in an application?
Technically speaking you are right. You may be able just to use one ConnectionFactory.
However it is a better design to use multiple ConnectionFactories depending on your requirements so the traffic would be spread out evenly and you do not run out of connections.
So if you know about a JMS Client application that may be problematic (the logic does not allow proper connection handling open/close), you may isolate it to use its own connection factory.
Also some connection factories allow a pool of 10 default active connections at the same time (it depends on the implementation/ settings) if you will need more you may use more than one connection factory.
I've configured a TopicConnectionFactory in ActiveMQ that receives chat messages from TopicPublishers and dispatch that to TopicSubscribers.
Very ambiguous statement. TopicConnectionFactory does not receive or send any messages. It is just one of the admin Objects used to create Connection which in turn creates Session which in turn creates your publishers and subscribers which publish and subscribe the messages.
why can't we use one instance of ConnectionFactory for creating connections to all the Topics (or Queues) configured in an application?
You definitely can. There is no one stopping you from doing that.
As per specs
A connection factory object encapsulates a set of connection configuration
parameters that has been defined by an administrator. A client uses it to
create a connection with a JMS provider.
So unless you have different configuration requirements you can use same ConnectionFactory to create multiple Connections. And yes as otc has mentioned above number of connections is one of the configuration parameter.

single jms consumer for multiple jms servers

I am using a distributed jms queue and weblogic is my app server. There are three jms servers deployed in my clustered enviroment. The producers just send the message using name of queue jndi lookup 'udq' for example. Now I have associated a consumer for each jms server and I was able to consume the message, no problem so far.
Here is question, can I have a single consumer to consume the messages from the 3 jms servers. The weblogic allows jndi naming for destination lookup with following syntax #
qsession1 = qcon1.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
qsession2 = qcon2.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
qsession3 = qcon3.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
queue1 = (Queue)ctx.lookup("JMSServer-1#UDQ");
queue2 = (Queue)ctx.lookup("JMSServer-2#UDQ");
queue3 = (Queue)ctx.lookup("JMSServer-3#UDQ");
qreceiver1 = qsession1.createReceiver(queue1);
qreceiver2 = qsession2.createReceiver(queue2);
qreceiver3 = qsession3.createReceiver(queue3);
qreceiver1.setMessageListener(this);
qreceiver2.setMessageListener(this);
qreceiver3.setMessageListener(this);
qcon1.start();
qcon2.start();
qcon3.start();
I have only one OnMessage implemented for the above consumer. This does not work. Any suggestions please..
No, you can't have a consumer receiving messages from more than one JMS server. A consumer can receive messages from only one JMS server. You need to create multiple consumers to receive messages from multiple JMS servers.
you can use "Queue Forwarding" function.
From online documentation of wls 10.3:
"Queue members can forward messages to other queue members by configuring the Forward Delay attribute in the Administration Console, which is disabled by default. This attribute defines the amount of time, in seconds, that a distributed queue member with messages, but which has no consumers, will wait before forwarding its messages to other queue members that do have consumers."
here a link: http://docs.oracle.com/cd/E13222_01/wls/docs103/jms/dds.html#wp1260816
You can configure this feature from administration of each single queue.

Websphere JMS with BUS

Hi I am new to the Websphere JMS. It is bit different configuration i.e we need to create BUS first. I also seen that Connection factory has service bus reference and same service reference is given in Queue. I have following understanding till now
We have enterprise BUS to special needs. i.e BUS has control over the messages before MDB.
We can filter,alter the message in the BUS.
What is relation between Connection factory and Queue.I just seen that Connection factory has same reference of BUS.
Why we refer the same BUS name in Connection factory and Queue.
Please correct my understanding and help me in finding answers of above questions.
SIBus is what holds the messaging engine(s) which contains destinations (point-to-point or publish/subscribe) and actually dispatch messages
In the JMS Part you got the Default JMS Provider which provides you JMS resources (Connection factories, Queues, Topics) which allows you to interact with the SIBus
In the SIBus you define a Destination on a messaging engine with some type (point-to-point or publish/subscribe)
A JMS Connection Factory creates connections to the messaging engine so you can send/receive messages, this is why you need to tell it which Bus you want it to create connections to
A JMS Queue referes to a point-to-point Destination in the SIBus.
Now for your questions:
The Bus itself is not intended to modify or filter messages
Filtering can be done by using a message selector in the MDB, when the MDB attach to the destination it will provide the message selector and the messaging engine will filter messages by it.Regarding modification I am not sure
As I stated before,
ConnectionFactory is what creates connections to the messaging engine while the Queue is an abstraction to the SIB Destination. This is why you need to tell each one which Bus it is interacting with.
Why we refer the same BUS name in Connection factory and Queue.
One reason is that the buses configured in the connection factory and the queue are not necessarily the same. That is the case in a topology with buses that are interconnected using SIBus links. In that case, you can connect to a messaging engine in one bus to send messages to a destination in another bus.

Resources