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.
Related
I have an UI application (displays streaming) which makes a WebSocket connection to the Spring Boot microservice (multiple JVM'S) and this service forwards the request to one of the upstream servers and listens to the responses on a JMS queue coming from upstream server, which then response messages had to be returned to the socket.
Issue we are facing is since the socket is point to point, and the Spring Boot application is running on multiple instances which all are listening to the same JMS queue we are unable to serve the data back to the WebSocket when a message is received on a instance which the request to upstream wasn't made.
Here's the basic flow:
WebSocket -> instance1, instance2, instance3 -> Data provider
Instance1 made the request to data provider.
Data provider sends the data back to the queue
Instance 3 receives the message, but it doesn't have the socket connection to send the data back.
We had an interim solution using correlation id in JMS headers and selectors on the queue however now the data publisher is not able to provide the correlation id to depend on.
Does anybody have a better suggestion to address this?
Since you're using a request/reply pattern with JMS you must either use a correlation ID or a unique temporary queue for the response.
You indicated that, "the data publisher is not able to provide the correlation id to depend on." However, your application actually provides the correlation ID. The "data provider" in this case just needs to take it from the message it receives and put it into the response message. The process only requires 2 method calls by the "data provider" - javax.jms.Message.getJMSCorrelationID and javax.jms.Message.setJMSCorrelationID.
If the "data provider" can't do this then it's doubtful they will be able to accomplish the other option of using a unique temporary queue for the response. However, it's worth explaining in any case. When one of your "instance" servers sends the request message it first needs to use javax.jms.Session.createTemporaryQueue to create a temporary queue and then take the return parameter of that method and set it on the request message using javax.jms.Message.setJMSReplyTo. When the "data provider" receives the message they will get this value using javax.jms.Message.getJMSReplyTo and then send the response to this queue where the "instance" will then retrieve it.
These are the two generally accepted ways to implement a request/response pattern with JMS. I don't know of any other ways to implement such a pattern.
how is that possible that a REST Microservice can communicate with another Microservice which is a hybrid, which means he can communicate with REST and with a Message Queue. For Example an API-Gateway. For the outside world, he is able to communicate with an App, Mobilephone via REST but the communication from the backend is via message queue.
Use case:
My homepage wants to get a Vehicle from the database. He asks the API-Gateway via a GET-Request. The API-Gateway takes the GET-request and publishes it into the message queue. The other Microservice takes the message and publishes the result. Then the API-gateway consumed the result and send it back as a response.
How can I implement it? Am I using Spring boot with Apache Kafka? Do I need to implement an asynchronous communication?
(Sorry its german)
There are some approaches to solve this situation.
You might create topics for each client request and wait for the reply on the other side, e.g, DriverService would read the request message, fetch all your data and publish it to your client request topic. As soon as you consume the response message, you destroy that topic.
BUT 'temporary' topics might take too long to be delete(if no configuration avoids that, such as delete.topic.enable property) in a request-response interaction, and you need to monitor possible topics overgrowth.
Websocket is another possible solution. Your client would start listening to a specific topic, previously agreed with your server, then in a specific timeout you would wait for the response, when your DriverService would publish to that specific socket channel.
Spring Boot offers you great starters for Kafka and Websockets. If you are expecting a large amount of transactions, I would go with a mixed strategy, using Kafka to help my backend scale and process all transactions, then would respond to client via Websocket.
I'am trying to understand the topology of queues and exchanges MT creates in RabbitMQ.
I cannot get these two statements:
we generate an exchange for each queue so that we can do direct sends
to the queue. it is bound as a fanout exchange (is it about sending vs publishing?)
control queues are exclusive and auto-delete - they go away when you
go away and are not shared.
What for does MT need to send direct messages? Does this relate to control queues used by MT internally?
There is also no mentioning about dead letter queue, does that imply MT does not support one out of the box?
Oops, looked in a wrong place. It's here.
Michael Aldworth has described this in details in his excellent MassTransit Send vs. Publish blog post.
Essentially, for each MT endpoint, you get a exchange-queue pair, which is named after the queueName parameter value in the endpoint configuration. Topics, at the other hand, are RabbitMQ exchanges named after the message contract full type name.
Publish
You send a message to the topic, meaning to the message type exchange. MassTransit creates binding between the message type exchange and queue-name exchange on start up. In such way subscriptions work on the RabbitMQ levels. Publisher never knows who will be receiving the published message, if anyone at all.
Send
When sending, however, you need to specify the receiver address. By doing this you instruct MassTransit to deliver the message directly to the queue-name exchange. There is no binding between message-type exchange and queue-name exchange involved here. Therefore, the message will be delivered even if there is no consumer for this type of message at the target service. In such case the message will be moved to the deadletter queue (queue-name_Skipped).
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.
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.