RabbitMQ is sending the request again if response is null - rabbitmq

I am using RabbitMq with masstransit for messaging between different services, let us say that we have the following scenario:
First service asks about specific info from second service by sending a request.
Second service looks for the info in database and respond with an object containing the found info.
In case there is no info available in database, the second service responds with a null object.
The issue is that RabbitMQ is considering that the request has failed thus it keeps sending the request again.
Can I configure the bus to consider the null reponse as a normal response?

You cannot reply with null object. You have two options:
Add a boolean property to your response indicating it is not a success
Throwing an exception in the request consumer, then the fault message will be sent to the request client.

Related

Mass Transit - Are messages still delivered after timeout with RabbitMQ

This may be a very stupid question but I haven't been able to find a definitive answer online. I'm using the Masstransit Request/Response pattern with RabbitMQ as my message broker.
I have a request to add a user to a database and a consumer running in a separate service that consumes that request and sends a response.
The request has a ten second timeout. My question is: If that request timed out before the consumer was able to consume it, is the request removed or will it eventually get consumed by the consumer and the request client just times out and moves on?
The request client is for requests, which by default have a 30 second timeout (which you indicated you are changing to ten seconds). This setting applies to both the request client timeout (the point at which it stops waiting for a response) and the time-to-live of the message sent.
If you want to extend the message TimeToLive, you can change that value when sending the request using:
await client.GetResponse<T>(request, x =>
x.Execute(context => context.TimeToLive = TimeSpan.FromDays(10)));
TL;DR - yes, the request message will expire after 10 seconds and by automatically removed from the queue by the message broker.

Writing tests with http request without response

I need to prepare a Java test (citrus framework) which initial step is sending a http request. Unfortunately my app under tests does not reply to this http request with anything while my testing framework expects to have a response and generates an error otherwise. The best way to deal with such a situation which came to my mind is to use some kind of a proxy between my testing framework and actual application which will forward the test request to the actual application and reply back to the testing framework with OK status not waiting for the response from app.
Does it make a sense? How could I prepare such a proxy assuming that my tests are to be running with maven invocation?
I see following options:
Fire and forget: send the Http request (using the fork mode on the send operation in Citrus) and do not care for the response at all. Just leave out the receive message action to ignore the response in Citrus.
Expect the timeout: Send the Http request and use the receive timeout action to verify that the client does not receive a response in the given time
Assert/catch the timeout exception: Use the assert or catch action in Citrus to handle the timeout exception when sending the http request
Personally I would go for the option #2 where you send the Http request and verify that there is no response for a given amount of time. This makes sure that the actual behavior of your application to not send any response does not change over time.

Unable to Pull Message off Queue

Let me explain my configuration:
ActiveMQ 5.12.0
AnyPoint Studio 5.2.1
Mule 3.6.1
Flow of application:
I am using FunctionalTestCase to post and retrieve a message from queue.
MuleClient client = muleContext.getClient();
String productAsJson = "{\"name\":\"Widget\", \"price\":9.99, \"weight\":1.0, \"sku\":\"abcd-12345\"}";
client.dispatch("http://localhost:8081/products", productAsJson, null);
MuleMessage result = client.request("jms://products", RECEIVE_TIMEOUT);
What is happening is the message is getting posted but when I try to retrieve it, I get the string "{NullPayLoad}".
After stepping back through the flow, I have discovered the message payload, when using the Mule Client, is not making the queue. While looking through the admin console for ActiveMQ, I discovered the message details is "{NullPayload}". When I check using the Advance Risk Client, the JSON message is getting posted correctly.
Any suggestions would be greatly appreciated.
Russ
It's NullPayload when using the MuleClient because by default the http operation will be GET and wont be expecting a body to parse.
The MuleClient is more suited to working with Mule transport infrastructure such as the JMS transport or the old http transport. I don't think it plays nice with the new http listener module.
Normally with the transports you can set the method via a property but that doesnt seem to work with the http:listener:
MuleMessage message = getTestMuleMessage();
message.setPayload(productAsJson);
message.setProperty("http.method", "POST", PropertyScope.INBOUND);
client.send("http://localhost:8089/products", message);
I would suggest using a standard HTTP client such as Apache HTTP client etc. and set the method to POST/PUT or whatever method you need to use that expects a body.

receiving an input file dynamically and put my mule application in listening

Scenario:
- An application want to send a push to a list of device.
- so she sends information to my mule application which must be listening to the arrived information.
- My application will send this information via web service to the application which will send the push and then my application will wait for a response which is a json file with content: success: 0/1 failed: 0/1,
- according to this answer my mule application will send email which i take from the database, if the device concerned didn't receive the push.
I have done the last part of this scenario. from the receipt of the answer of the push. Now I have some questions about the first part:
I guess that the application sends a json file that contains a list of information of each device.
How processed the list of information devices. I must loop on the contents of the json file. any example of this?
How to put my application in listening for the arrivals request for sending push?
is the http connector sufficient? if so how to configure the path variable.
I'm using mule 3.5.0 CE, Thank you in advance.
Lets break this down, to the various components:
Sender Application - this is the service that needs to communicate with the devices.
Device Controller - this is the application that talks to the hardware devices.
Proxy - this is what you are developing on the Mule ESB. It will connect to both the Sender Application, and the Device Controller and transfer the request from Sender to Controller; and then send the results from the Controller back to the Sender.
The flow would look something like this:
Sender Application needs to communicate with devices.
Sender Application transmits information using JSON.
Proxy receives this JSON request.
The Proxy then contacts the Device Controller over HTTP.
The Device Controller only talks to the Proxy, and returns a result of 0 or 1 depending on the result from the physical device.
The Proxy then needs to communicate this result to the Sender Application.
At first, you might think to develop your Proxy over HTTP (using the HTTP Connector). This connector creates a web service endpoint (a website, basically) that can listen and respond to requests.
The Sender Application connect to this endpoint over HTTP and submits the JSON document containing the commands to be executed.
Your proxy then immediately contact the Device Controller (again, over HTTP using the same connector).
The device controller talks to the devices, and then returns the response to your Proxy (over HTTP).
You take this response and then send it back as the response to the original HTTP request (from the Sender Application).
The problem here is if there is any delay between your connection and the Device Controller (or the Device Controller and the physical devices), the connection will remain blocked on both sides (since you need to send a response).
If there is a large delay the HTTP connection between your Proxy and Sender Application may terminate.
This is the same when some site is overloaded and doesn't respond - eventually the browser will timeout.
To avoid this scenario, split your integration into three separate flows.
The first flow will create a normal HTTP connection to which the Sender Application will upload the JSON document. It will take the JSON document and convert each entry into a message using the batch module (note: this is only available in the Enterprise edition - for the CE version you'll have to code this logic yourself). Next, take this message and put them in a separate queue. Return the unique ID of this message as a JSON response back to the Sender Application.
Your second flow is listening on this queue and whenever a message arrives, it connects to the Device Controller and gets the response. The response is then written to another queue.
Your third and final flow listens on this results queue, takes each message on this queue and converts it to JSON/XML. It then has a HTTP connector where it can be queried for results for each command.
In the above setup, your Sender Application can drop a large JSON file of commands to be executed; for each command, a unique ID will be returned to the Sender Application.
It will then query the result endpoint (what your last flow exposes) and send it the message ID. The result endpoint will then check the status of this request and respond with the appropriate code.
Here is an example of how this would work (from the point of view of the Sender Application):
I is the input to your flow, O is the result sent.
Step 1 - send a request for commands to be executed:
I: Sender Application > http://localhost:8080/input-commands?device=1&command=Y
O: <command><req-status>OK</req-status><id>1234-123</id></command>
Step 2 - Query results:
I: Sender Application > http://localhost:8080/result?id=1234-123
O: <command><id>1234-123</id><result>0</result></command>

Spring Integration: How to send response packet to client in case of exception using error-channel?

I am using Spring Integration in my project.
Endpoints used in application are in-bound gateway, header based router, transformer, spliter, service activator.
In case of success flow(not any exception), in-bound gateway reply-channel getting desired response and client gets that response which is fine but in case of any exception, I want to send customized error response which is not working as per my requirement.
I am using error-channel to accomplish above requirement but not succeeding in that.
Please find my configuration of in-bound gateway, error channel etc.
I have not use any chain in configuration.
<int-http:inbound-gateway id="inboundGateway"
supported-methods="GET, POST" request-channel="requestChannel"
path="/services/tylv/{requestParam}" reply-channel="responseChannel"
error-channel="errorChannel">
</int-http:inbound-gateway>
<int:transformer ref="errorHandler"
input-channel="errorChannel" method="generateErrorResponse"
output-channel="responseChannel" />
<bean id="errorHandler"
class="com.csam.wsc.enabling.integration.transformer.ErrorHandler" />
In case of exception , com.csam.wsc.enabling.integration.transformer.ErrorHandler.generateErrorResponse(ErrorMessage) successfully called.This API handle exceptions, generate Error Response Packet but it is not being sent to client, just only HTTP Status Code 200 sent.
Ideally it should be sent because transformer's output-channel is reply-channel of inbound-gateway which is already sending response packet along with status code 200 in case of success (no any exception).
I think in case of error-channel , in-bound gateway reply-channel is not working, but I am not sure.
Please help me in configuring error-channel.
You should store the message's headers before the error reaches the error channel and then you should create a new message with the stored headers and route that new message to response channel.
MessageBuilder.fromMessage(errorResponseMessage).copyHeadersIfAbsent(storedHeaders).build();