I am studying for the Spring Core certification and I have some doubt about how JMS works and about how Spring handle it.
So I know that the JMS Core Components are:
Message
Destination
Connection
Session
MessageProducer
MessageConsumer
From what I have understand a Message is what is send and shared with other entities (other products that have to consume this data) and a message can have differents shapes: TextMessage, ObjectMessage, MapMessage, BytesMessage and StreamMessage.
Ok, from what I understand the Destination component of the JMS Core Components defines who receives messages and the logic for dispatching messages.
So I know that I have 2 kinds of destinations that are:
Queue: that define a point to point message. From what I have understand I can have some Message Producer that put the generated messages into a queue and then I have some MessageConsumer that consume message. Each message can be consumed by a single MessageConsumer.
Now my doubt is: a MessageConsumer consume message putted into the queue by a specific MessageProducer (there is something like a 1 to 1 relationship between MessageConsumer and MessageProducer) or a MessageProducer put an id related to the specific MessageConsumer that have to read the message that it put into the queue?
So for example, in the first case if I have 2 MessageProducer respectivelly named Producer-1 and Producer-2 I need to have 2 MessageConsumer named Consumer-1 and Consumer-2 where Consumer-1 consume messages produced from Producer-1 and Consumer-2 consume messages produced from **Producer-2).
Instead in the second case the Consumer-1 can consum messages produced by from both Producer-1 and Produer-2 because the MessageProducer put a message in the queue specifying who is the MessageConsumer that have to consume the message.
How exactly works? What is the correct logic?
if I have 2 MessageProducer respectivelly named Producer-1 and
Producer-2 I need to have 2 MessageConsumer named Consumer-1 and
Consumer-2 where Consumer-1 consume messages produced from Producer-1
and Consumer-2 consume messages produced from **Producer-2).
Not really. The message consumer is connected to the queue and it will receive all messages that are put in the queue irrespective of the Producer. So if you have two producers that put a message each in the queue, it will be consumed by the single consumer connected to it.
If you wish to have messages produced by different producers targeted to specific consumers, you should use a concept known as 'message selectors'. To achieve this, Message producers should add 'headers' to the messages (system headers or custom ones) and then message listeners can specify that they receive messages that match a specific header.
Related
I have a rabbitmq queue and two spring cloud spring consumers.
I want that each consumers process messages in order.
I thought that when consumer1 send ack, consumer2 receive second message,
so I expected message1, message2 is processed in order in each consumers.
-------------------- time pass ------------------------>
consumer1: message1 message3
consumer2: message2 message4
But it wasn't. consumer1, consumer2 receive message1, message2, and process simultaneously.
-------------------- time pass ------------------------>
consumer1: message1 message3
consumer2: message2 message4
Is there a way for spring cloud stream to consume messages exclusively?
RabbitMQ (AMQP) doesn't support that; each consumer gets prefetch messages.
It does support exclusive consumers, but it means consumer1 would get all the messages and consumer2 would only get messages if consumer1 dies.
However, Spring Cloud Stream doesn't currently provide a property to set that option.
you would have to model your queues in a different way. E.g. by having an "incoming" queue which has exactly one consumer-coordinator. This consumer would relay messages to the "work" queue where consumer1+2 are both waiting and pick up work in a round robin way.
They would then signal completion to the coordinator on a third queue which would cause it to resume relaying a single message to the work queue.
We have the following scenario.
Queue: Q1
Q1 binds to Exchange1 and Exchange2.
Message A published to both Exchange1 and Exchange2.
We have Q1 Consumer defined.
How will be the behavior in this case. Does the message consumed twice?
Does the message consumed twice?
Yes.
If you publish the message to both Exchange 1 and Exchange 2, and both of these exchanges push the message to Q1, then you consumer will have 2 messages to consume.
Here's my scenario. The program is developed with publisher/subscriber methodology. Have two topics (topic1, topic2) in producer and consumer part. I need to get the acknowledgement of the received topic1 from consumer in producer program so that when the acknowledgement status is true, the producer program will have to send the message on topic2.
Had googled links suggesting session.CLIENT_ACKNOWLEDGE in consumer. But I'm in need of the Acknowledgement status to be returned to producer for further process.
JMS specification does not define any API for a publisher to know if a message was consumed by a subscriber or not. A publisher just publishes a message and it is the messaging provider/broker to deliver that message to subscriber. A broker will deliver the message if there is a subscription otherwise that message is discarded.
The session.CLIENT_ACKNOWLEDGE option is one of the way a consumer tells a messaging provider (not producer) to remove the message from it's queue/memory. There are couple of other acknowledgement options as well but all these options are for telling a messaging provider to remove the message but not telling a producer.
If producer requires an acknowledgement from a consumer, then consumer will have to publish an acknowledgement message on another topic and producer subscribes to that topic to receive those acknowledgements. For example:
Producer publishes on TOPIC1
Producer subscribes to TOPIC1/ACKS
Consumer subscribes to TOPIC1
After receiving a message
Consumer publishes an acknowledgement message to TOPIC1/ACKS
Producer will receive the acknowledgement message.
It can then publish on TOPIC2
You must note that there can be multiple acknowledgement messages as there can be more than one subscribers on TOPIC1.
If your program contains only one message producer, you can create a Queue in the message consumer and let the producer subscribe to that Queue. In the Queue mode, it's point-to-point. So the message will only be delivered from the consumer to the producer.
Alternatively, you can also use setJMSReplyTo method to specify the Queue you want the consumer reply to when it receives the message from the producer. This way you don't need to create the Queue explicitly in the consumer but you can create the Queue in the producer as well. But you still need to let the producer listen to that Queue to received the acknowledgement.
There might be a stupid simple answer to this, but I'm trying to use ActiveMQ to pass messages between producers and consumers. I will have many producers and many consumers, but I want each message to be delivered only once among the consumers. This would seem to mean that I cannot use Topics, since they would deliver messages to all consumers who are listening, and I want only one Consumer to receive each message.
My problem is that I am able to receive messages, but the messages are not dequeued. So if I restart my consumer process, all of the messages are reprocessed. This answer seems pertinent but does not seem to apply since I can't create durable queue consumers, only durable topic consumers (unless I'm missing something in the API docs).
My code is as follows.
TopicConnectionFactory factory = new ActiveMQConnectionFactory(props.getProperty("mq.url"));
Connection conn = factory.createConnection();
Session session = conn.createSession(true, Session.CLIENT_ACKNOWLEDGE);
Queue queue = session.createQueue(props.getProperty("mq.source_queue"));
conn.start();
MessageConsumer consumer = session.createConsumer(queue);
Then later on
Message msg = consumer.receive();
msg.acknowledge();
if (!(msg instanceof TextMessage)) continue;
String msgStr = ((TextMessage)msg).getText();
This is my current code. I have tried with Session.AUTO_ACKNOWLEDGE and without msg.acknowledge(). Any working permutation of this code seems to retrieve the messages, but when I restart my consumer, all of the messages get received again, even if they have been received prior to the restart.
You created the session as a transacted Session and therefore need to call, session.commit if you want to inform the broker that all messages are now consumed and don't need to be redelivered. If you don't set the first argument to createSession to true then the Ack mode is respected otherwise its ignored, one of the oddities of the JMS API I'm afraid. If you do this:
ConnectionFactory factory = new ActiveMQConnectionFactory(props.getProperty("mq.url"));
Connection conn = factory.createConnection();
Session session = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
Queue queue = session.createQueue(props.getProperty("mq.source_queue"));
conn.start();
MessageConsumer consumer = session.createConsumer(queue);
Then this would work:
Message msg = consumer.receive();
msg.acknowledge();
Otherwise you need to do:
Message msg = consumer.receive();
session.commit();
But keep in mind that for a single message transactions don't really make sense to client ack with no transaction is a better option.
I have a Message Producer running on one JVM that puts in messages in a JMS Queue .I have a Message Consumer which implements Message-Driven-Bean and MessageListener interface that listens to this queue.This Message consumer is on a different JVM.
The producer puts in messages in the queue properly.But the MDB is not able to pop out messages from queue.The weird thing is that when I restart my Message Consumer , all the messages in the queue are popped out by the Message Consumer at once.After this,no matter how many messages producer puts in the queue ,the Message Consumer does not pop them out.
What could be the reason??
The application server I am using is JBOSS4.0.5.GA.
Thanks
Please provide more details. From what you have provided:
is your consumer running and waiting for messages ? (inside some sort of while loop or a blocking call)
you can set prefetch size for your consumer to be 1 in your jms connection settings so that it fetches only 1 (or whatever number) message from the queue.