How to configure Spring Amqp #RabbitListener not to throw exceptions when queue does not exist? - amqp

This is my #RabbitLister code:
#RabbitListener(queues = device.*)
I want this listener to listen all the queues, created by devices on my broker where * is ID of device, like:device.1
Currently, when i start my app and queues are not created, i'm getting an exception:
ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no queue 'device.*' in vhost '/'
What i'm doing wrong?

Wildcards/patterns in queue names are not supported by AMQP/RabbitMQ.
Devices should only send messages to exchanges with routing keys; consumers are responsible for queues not producers.
Use a topic exchange with routing keys device.1 etc and bind a single queue with routing key device.#.

Related

Use same JMS ClientID for multiple destinations/topics

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.

RabbitMQ queue gets deleted immediately after creation. Why?

I'm trying to deploy Spring Boot microservices applications producing and consuming data using RabbitMQ on K8s Cluster in Azure AKS.
When I run producer application and produce a message to the queue through POSTMAN, I get 200 OK response but in RabbitMQ management UI, I get no queues and in the RabbitMQ container logs I see below error
o.s.a.r.c.CachingConnectionFactory : Channel shutdown: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'employeeexchange' in vhost '/', class-id=60, method-id=40)
Not able to figure out what I'm doing wrong.
If you have any idea (or need any kind of additional information), let me know.
You can use below to create a queue
#Bean
Queue queue() {
return new Queue(String name, boolean durable, boolean exclusive, boolean autoDelete)
Parameters:
name - the name of the queue.
durable - true if we are declaring a durable queue (the queue will survive a server restart)
exclusive - false if we are not declaring an exclusive queue (the queue will only be used by the declarer's connection)
autoDelete - false if the server should not delete the queue when it is no longer in use

How to specify topic or queue when sending/subscribing to a JMS object, ActiveMQ Artemis and STOMP

I'm using ActiveMQ Artemis messaging system, and I'm testing my setup with STOMP (stomp.py).
I created an "address" on Artemis called Site.SOF.Order.Fulfillment.Submission.ActiveOmni.Topic, and attached two queues to it:
Site.SOF.Order.Fulfillment.Submission.ActiveOmni.queue (multicast)
Site.SOF.Order.Fulfillment.Submission.ActiveOmni.log.queue (multicast)
Here are the exported bindings:
<bindings>
<address-binding routing-types="ANYCAST" name="DLQ" id="2"/>
<address-binding routing-types="ANYCAST" name="ExpiryQueue" id="6"/>
<address-binding routing-types="MULTICAST" name="activemq.notifications" id="10"/>
<address-binding routing-types="MULTICAST" name="Site.SOF.Order.Fulfillment.Submission.Topic" id="92"/>
<queue-binding address="Site.SOF.Order.Fulfillment.Submission.Topic" filter-string="" name="Site.SOF.Order.Fulfillment.Submission.log.Queue" id="97" routing-type="MULTICAST"/>
<queue-binding address="DLQ" filter-string="" name="DLQ" id="4" routing-type="ANYCAST"/>
<queue-binding address="ExpiryQueue" filter-string="" name="ExpiryQueue" id="8" routing-type="ANYCAST"/>
<queue-binding address="Site.SOF.Order.Fulfillment.Submission.Topic" filter-string="" name="Site.SOF.Order.Fulfillment.Submission.ActiveOmni.Queue" id="94" routing-type="MULTICAST"/>
</bindings>
I created a user with access to Site.*
So how do I access the queues? For example, if I use the stomp.py command line tool like so:
> subscribe Site.SOF.Order.Fulfillment.Submission.ActiveOmni.queue
I get the error:
[username] does not have permission='CREATE_ADDRESS' on address Site.SOF.Order.Fulfillment.Submission.ActiveOmni.queue
So I try adding /queue/ to the front, as I've seen in the tutorials
> subscribe /queue/Site.SOF.Order.Fulfillment.Submission.ActiveOmni.queue
But I get the same error:
[username] does not have permission='CREATE_ADDRESS' on address /queue/Site.SOF.Order.Fulfillment.Submission.ActiveOmni.queue
I can send to the topic/address without trouble. The following results in a "hello" message appearing in both queues.
send Site.SOF.Order.Fulfillment.Submission.ActiveOmni.Topic "hello"
Is this a naming convention I'm missing? Or a way to specify topic vs queue? What am I missing here that's too obvious to be clearly documented?
Let me provide some background information first...
The ActiveMQ Artemis address model includes 3 main elements - addresses, queues, and routing types. These are low-level entities which are used to implement all the different semantics for all the different protocols and configurations the broker supports.
STOMP, by contrast, just supports ambiguous "destinations." The STOMP 1.2 specification says this about destinations:
A STOMP server is modelled as a set of destinations to which messages can be sent. The STOMP protocol treats destinations as opaque string and their syntax is server implementation specific. Additionally STOMP does not define what the delivery semantics of destinations should be. The delivery, or “message exchange”, semantics of destinations can vary from server to server and even from destination to destination. This allows servers to be creative with the semantics that they can support with STOMP.
In the core address model messages are sent to addresses and consumed from queues. Addresses and queues are named independently so the names that the core producer and consumer use can be different.
ActiveMQ Artemis supports both point-to-point and pub/sub semantics for STOMP destinations. You can read more about how to configure these semantics in the latest ActiveMQ Artemis STOMP documentation.
In the STOMP point-to-point use-case a message is sent to a destination and consumed from that same destination. The name that both the STOMP producer and consumer use are the same. In order to support these semantics the broker uses a core address and a core anycast queue with the same name.
In the STOMP pub/sub use-case a client creates a subscription on a destination which it can then use to receive messages sent to that destination. The name that both the STOMP subscriber and producer use are the same. In order to support these semantics the broker uses a core address and a core multicast queue with different names. The name of the core queue is generated by the broker automatically. The subscriber can then receive the messages directly from the underlying core subscription queue.
All this stuff is done behind the scenes for STOMP clients, but it's important to understand how STOMP maps to ActiveMQ Artemis' address model so you can configure things appropriately
In your case you've configured an address with 2 multicast queues and you're trying to consume from those queues. This use-case is a mix between point-to-point and pub/sub because you have statically defined queues (i.e. not queues auto-created by the broker in response to a subscriber) but the queues are multicast. These queues are like statically configured durable subscriptions. To access the queues directly you need to use their fully-qualified queue name (i.e. FQQN) from your client. The FQQN follows the pattern of <address>::<queue> so in your case you'd use either
Site.SOF.Order.Fulfillment.Submission.ActiveOmni.Topic::Site.SOF.Order.Fulfillment.Submission.ActiveOmni.queue
or
Site.SOF.Order.Fulfillment.Submission.ActiveOmni.Topic::Site.SOF.Order.Fulfillment.Submission.ActiveOmni.log.queue

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).

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.

Resources