One of our customers has a JMS based implementation in which there are queues for reading/writing messages. The JMS client needs to write to an outbound queue and the it will read the response from an inbound queue. The JMS client will be deployed across multiple sites and will talk to a single outbound queue for writing messages and will read from a inbound queue (one only) for the responses. Consider the scenario in which there are 100 unique outbound requests and then the consumer gets 100 different responses for the sent requests (assume the messages got delivered correctly). How do I ensure that the messages that the consumer is reading from the inbound queue is for the designated recipient? Do we have to write our own logic to map the request/response? or does JMS have any delivery mechanism based on connection id … etc so that message get delivered to correct requester. Thank you very much in advance, need your expert inputs to design the application correctly. The JMS provider I am using is Apache ActiveMQ.
Regards,
Sumeet C
It sounds like you need REQUEST/REPLY...
Request/Reply - Synchronous
A queue sender sends a REQUEST message, then in the same thread, receives a REPLY. The sending thread blocks until the receiver sends back a reply message, ensuring the reply is for the original request. It's a basic set up that uses temporary queues, REPLY_TO addressing, and JMSCorrelationID...
Apache ActiveMQ Request/Reply
EAI Patterns for JMS Request/Reply
Point-to-Point - Async
If the customer's JMS implementation provides distinct queues for sending requests and receiving replies, you can send messages asynchronously with a unique JMSCorrelationID, and provided the customer sends back a response with that same id, you can receive the response message in a different thread and correlate them with the original request based on the JMSCorrelationID. Technically-speaking, REQUEST/REPLY does the same thing except it blocks and uses temporary queues for sending response messages back to the requestor instead of explicitly-named queues.
Related
I'm evaluating NATS for migrating an existing msg based software
I did not find documentation about msg timeout exception and overload.
For Example:
After Subscriber has been chosen , Is it aware of timeout settings posted by Publisher ? Is it possible to notify an additional time extension ?
If the elected subscriber is aware that some DBMS connection is missing and cannot complete It could be possible to bounce the message
NATS server will pickup another subscriber and will re-post the same message ?
Ciao
Diego
For your first question: It seems to me that you are trying to publish a request message with a timeout (using the nc.Request). If so, the timeout is managed by the client. Effectively the client publishes the request message and creates a subscription on the reply subject. If the subscription doesn't get any messages within the timeout it will notify you of the timeout condition and unsubscribe from the reply subject.
On your second question - are you using a queue group? A queue group in NATS is a subscription that specifies a queue group name. All subscriptions having the same queue group name are treated specially by the server. The server will select one of the queue group subscriptions to send the message to rotating between them as messages arrive. However the responsibility of the server is simply to deliver the message.
To do what you describe, implement your functionality using request/reply using a timeout and a max number of messages equal to 1. If no responses are received after the timeout your client can then resend the request message after some delay or perform some other type of recovery logic. The reply message should be your 'protocol' to know that the message was handled properly. Note that this gets into the design of your messaging architecture. For example, it is possible for the timeout to trigger after the request recipient received the message and handled it but before the client or server was able to publish the response. In that case the request sender wouldn't be able to tell the difference and would eventually republish. This hints that such type of interactions need to make the requests idempotent to prevent duplicate side effects.
Let me start by describing the system. There are 2 applications, let's call them Client and Server. There are also 2 queues, request queue and reply queue. The Client publishes to the request queue, and the server listens for that request to process it. After the Server processes the message, it publishes it to the reply queue, which the Client is subscribed to. The Server application always publishes the reply to the predefined reply queue, not a queue that the Client application determines.
I cannot make updates to the Server application. I can only update the Client application. The queues are created and managed by the Server application.
I am trying to implement request/reply pattern from Client, such that the reply from the Server is synchronously returned. I am aware of the "sendAndReceive" approach with spring, and how it works with a temporary queue for reply purposes, and also with a fixed reply queue.
Spring AMQP - 3.1.9 Request/Reply Messaging
Here are the questions I have:
Can I utilize this approach with existing queues, which are managed and created by the Server application? If yes, please elaborate.
If my Client application is a scaled app (multiple instances of it are running at the same time), then how do I also implement it in such a way, that the wrong instance (one in which the request did not originate) does not read the reply from the queue?
Am I able to use the "Default" exchange to my advantage here, in addition to a routing key?
Thanks for your time and your responses.
Yes; simply use a Reply Listener Container wired into the RabbitTemplate.
IMPORTANT: the server must echo the correlationId message property set by the client, so that the reply can be correlated to the request in the client.
You can't. Unlike JMS, RabbitMQ has no notion of message selection; each consumer (in this case, reply container) needs its own queue. Otherwise, the instances will get random replies and it is possible (highly likely) that the reply will go to the wrong instance.
...it publishes it to the reply queue...
With RabbitMQ, publishers don't publish to queues, they publish to exchanges with a routing key. It is bad practice to tightly couple publishers to queues. If you can't change the server to publish the reply to an exchange, with a routing key that contains something from the request message (or use the replyTo property), you are out of luck.
Using the default exchange encourages the bad practice I mentioned in 2 (tightly coupling producers to queues). So, no, it doesn't help.
EDIT
If there's something in the reply that allows you to correlate it to a request; one possibility would be to add a delegating consumer on the server's reply queue. Receive the reply, perform the correlation, route the reply to the proper replyTo.
I have a project where I send AMQP messages to a RabbitMQ Server. This messages are synchronous messages (I use sendAndReceive method). So, I have a SimpleMessageListenerContainer configured with the RabbitTemplate as MessageListener, and the response queue is fixed (setReplyAddress in the RabbitTemplate).
If I have a multithreading server (Tomcat) where it is possible to send some messages simultaneously, could there be a problem if the response doesn’t arrive in order or the application send a message before a response to another message has arrived?
The responses are paired with requests using correlationId header. Clients have to set it to unique value for every request and the server has to set the same value the response queue. That way a client can pair the messages even when they arrive in arbitrary order.
From the RabbitMQ tutorial:
In the method presented above we suggest creating a callback queue for every RPC request. That's pretty inefficient, but fortunately there is a better way - let's create a single callback queue per client.
That raises a new issue, having received a response in that queue it's
not clear to which request the response belongs. That's when the
correlationId property is used. We're going to set it to a unique
value for every request. Later, when we receive a message in the
callback queue we'll look at this property, and based on that we'll be
able to match a response with a request. If we see an unknown
correlationId value, we may safely discard the message - it doesn't
belong to our requests.
My requirement is that:
I have an IBM MQ which is shared across 20 servers and runs the JMS client. Now there will be a specific message in the queue which is intended for a particular thread. The thread need to use a correlationID to fetch the message from all the messages in the MQ.
When I am using onMessage() it is uncertain which thread will Listen to the message. Suppose server-1 is waiting for the message but server-15 listens it. Server-1 gets eventually timed out even though there was a message intended for the thread in server-1.
Please suggest how we are going to handle this scenario without introducing major performance issue.
Use a MessageSelector on the listener container(s). If the correlationId is in the standard JMSCorrelationID header the selector would be JMSCorrelationID=foo to receive all foo messages.
I am trying to use spring integration and bit confused about outbound gateway. Below is my question.
This is what I understand about outbound gateway.
Spring integration amqp outbound gateway takes messages from requestChannel and write it to rabbitmq queue (requestQueue) and waits for reply on rabbitmy replyQueue. Once the reply is available, it reads and add it to responseChannel.
The question is, if multiple requests are being sent concurrently by multiple job instances and responses for different requests by different jobs are available on same rabbitmq replyQueue.
Then how does outbound gateway choose responses ? Does it use correlation id to fetch only responses to request sent by the same gateway and ignores other responses ?
It depends on how the gateway is configured; by default a separate (auto-delete) reply queue is created for each request.
If it is configured with a RabbitTemplate that uses an explicit reply queue (and a reply-listener), the template does the correlation internally, by setting a correlationId on the message. That way, each reply is returned to the proper caller.
You need to be sure to set the reply-timeout on the outbound gateway to a large enough value; it defaults to 5 seconds.
EDIT:
Note that in order to concurrently run jobs (per your other question), you must use the default reply routing and not a dedicated reply queue. Unlike JMS, AMQP does not have a message selector so you can't have multiple gateways using the same reply queue.