How to handle timeout exception when using jms outbound gateway? - spring-integration

I have a jms outbound gateway like this:
<jms:outbound-gateway request-destination = "requestQueue"
reply-destination="replayQueue"
request-channel="sendToJmsChannel"
reply-channel="receiveFromJmsChannel"
receive-timeout="5000"/>
In my spring integration flow I send requests to 'sendToJmsChannel' and handle replies from 'receiveFromJmsChannel'
The question is, how can I handle the case when the receive-timeout is elapsed and no reply was returned to the reply-destination?

The JmsOutboundGateway thorws:
throw new MessageTimeoutException(message,
"failed to receive JMS response within timeout of: " + this.receiveTimeout + "ms");
In case of that timeout (5 sec by default).
You can configure <retry-advice> within <request-handler-advice-chain> for the <jms:outbound-gateway> to resend the same message to the request-destination on that MessageTimeoutException. Or just handle it from the caller with regular try...catch, or in the ErrorHandler on the error-channel, if your flow starts from the <poller> or message-driven-ednpoint.
Otherwise it isn't clear what is your goal. The Exception in the Spring Integration doesn't provide more complexity as it is in the typical Java application.

Related

Http Inbound Gateway takes 2x timeout to send timeout response to client

We're using an http inbound gateway to process http requests. Lately , we wanted to set specific http response code that will be sent to user after a timeout.
We upgraded to spring 4.2.1 and set
the reply-timeout-status-code-expression attribute
and it's working now.
But there is a problem : if we set the timeout to 10 seconds , a ReplyTimeoutException is raised in the web application after exactly 10 seconds but the response arrives to the client after 20 seconds ( exactly the double ).
We changed the timeout several times but it always take 2x timeout for the response to be received by client.
This is the xml config for the http inbound gateway :
<int-http:inbound-gateway id="inboundRequest" request-channel="inbound-channel"
supported-methods="POST" path="/Request" error-channel="errorChannel" reply-channel="gateway_response"
reply-timeout="5000" request-payload-type="java.lang.String" reply-timeout-status-code-expression="'504'" >
A Help would be really appreciated
I see you have an error-channel - if the error flow returns no response, the reply timer starts again when the error flow ends (we're waiting for a reply from the error flow).
Instead of returning nothing from the error flow, you need to throw a MessageTimeoutException.
Turning on DEBUG logging and following the message flow is the best way to diagnose issues like this.
If that's not the problem, you need to show the rest of your configuration (edit the question, don't try to post it in a comment).

Spring Integration - TCP - Response Correlation

I'm new to Spring Integration. The situation is that I've to connect to Tcp server dynamically(i.e. the DNS will be dynamically generated at runtime based on some params). Because of this I'm using Service Activator to manually create Tcp Connections and send messages. I've overridden CachingClientConnectionFactory to make use of shared connections concept(with single-use='false'). I was listening to messages using TcpReceivingChannelAdaptor by overriding "onMessage" method. The problem is that the server either responds with a Success or failure(with Generic messages) with no CorrelationID. Is there any way to correlate the request with the response ?
I tried using TcpOutboundGateway, but with this approach also I get the same problem. I used TcpConnectionSupport to send messages :
//Sample Code.
final String correlationId = "" // Dynamic unique number
TcpOutboundGateway outboundGateway = new TcpOutboundGateway(){
public synchronized boolean onMessage(Message<?> message) {
ByteArrayToStringConverter converter = new ByteArrayToStringConverter();
String response = converter.convert((byte[]) message
.getPayload());
logger.info(correlationId);
return false;
}
};
DefaultCachingClientConnectionFactory connFactory = new DefaultCachingClientConnectionFactory();
TcpConnectionSupport con = connFactory.obtainConnection();
GenericMessage<String> msg = new GenericMessage<String>("Sample Message" + correlationId);
con.registerListener(outboundGateway);
con.send(msg);
// DefaultCachingClientConnectionFactory is the subclass of CachingClientConnectionFactory.
When I send multiple messages, every time I get the same correlation printed in the "onMessage" method.
I read here that Outbound Gateway will correlate messages. Please help me. Maybe I'm doing something wrong.
Thanks
Unless you include correlation data in the message you can't correlate a response to a request.
The gateway achieves this by only allowing one outstanding request on a socket at a time; hence the reply has to be for the request. This is not very useful at high volume with a shared connection; hence the caching client cf was introduced. The gateway keeps a map of outstanding requests based on the connection id.
The gateway, in conjunction with the caching client connection factory should do what you need. However, overriding onMessage is not a good idea, because that's where the reply correlation is done.

How could I add a delay in processing failed messages in ServiceStack Redis MQ

Is there an easy way to get Servicestack to wait x seconds before retrying a failed MQ item (using Redis MQ). At the moment it just tries 3 times consecutively with no delay.
When you register a MQ handler you can also register an error handler which gets called after publishing a failed message which you can use to add a custom delay, e.g:
mqServer.RegisterHandler<MyRequest>(
ServiceController.ExecuteMessage,
(msgHandler, msg, ex) => Thread.Sleep(1000));

JMS Outbound Gateway response read throttling

I have a JMS Outbound Gateway which sends messages out via a request queue and receives messages in via a response queue. I would like to know what is the simplest way to apply throttling to the receive part of messages off the response queue. I have tried setting a Poller to the Outbound Gateway but, when I set it, the response messages are not consumed at all. Can a Poller be used in Outbound Gateways for the purpose of message consumption throttling? If so, how? If not, how can I best throttle message response consumption instead?
My stack is:
o.s.i:spring-integration-java-dsl:1.0.0.RC1
o.s.i:spring-integration-jms:4.0.4.RELEASE
My IntegrationgConfig.class:
#Configuration
#EnableIntegration
public class IntegrationConfig {
...
#Bean
public IntegrationFlow testFlow() {
return IntegrationFlows
.from("test.request.ch")
.handle(Jms.outboundGateway(connectionFactory)
.receiveTimeout(45000)
.requestDestination("REQUEST_QUEUE")
.replyDestination("RESPONSE_QUEUE")
.correlationKey("JMSCorrelationID"), e -> {
e.requiresReply(true);
e.poller(Pollers.fixedRate(1000).maxMessagesPerPoll(2)); // when this poller is set, response messages are not consumed at all...
})
.handle("testService",
"testMethod")
.channel("test.response.ch").get();
}
...
}
Cheers,
PM
Since you are going to fetch messages from the response queue the .poller() doesn't help you.
We need poller if our endpoint's input-channel (in your case test.request.ch) is a PollableChannel. See docs on the matter.
There .replyContainer() option on the Jms.outboundGateway for you. With that you can configure concurrentConsumers options to achieve better throughput on response queue.
Otherwise the JmsOutboundGateway creates MessageConsumer for each request message.

Spring JMS Outbound Gateway receive timeout being ignored

I have a Spring Integration flow which sends a message out via a JMS Outbound Gateway which is configured to have a receive timeout of 45 seconds. I am trying to test the receive timeout period by sending a message out in a setup where the message is never consumed on the other side (therefore a response doesn't come back). However, when I run the test, the message is placed in the outbound queue but, the Outbound Gateway's receive timeout never occurs (after 45 seconds). Any ideas what reasons there could be for this happening (not happening)?
My stack is:
o.s.i:spring-integration-java-dsl:1.0.0.M3
o.s.i:spring-integration-jms:4.0.4.RELEASE
My IntegrationgConfig.class:
#Configuration
#EnableIntegration
public class IntegrationConfig {
...
#Bean
public IntegrationFlow testFlow() {
return IntegrationFlows
.from("test.request.ch")
.handle(Jms.outboundGateway(connectionFactory)
.receiveTimeout(45000)
.requestDestination("REQUEST_QUEUE")
.replyDestination("RESPONSE_QUEUE")
.correlationKey("JMSCorrelationID"))
.handle("testService",
"testMethod")
.channel("test.response.ch").get();
}
...
}
In terms of JMS configuration, the connection factory used is a standard CachingConnectionFactory which targets an MQConnectionFactory.
Thanks in advance for any help on this.
PM
--- UPDATE ---
I have turned on debugging and I can see that when the timeout occurs the following message is logged:
AbstractReplyProducingMessageHandler - handler 'org.springframework.integration.jms.JmsOutboundGateway#0' produced no reply for request Message: [Payload byte[835]][...]
Just need to find out how to capture this event in the flow?
--- UPDATE 2 ---
The message being sent out has an ERROR_CHANNEL header set on it to which I would expect the timeout exception to be routed to - but this routing does not happen?
Is it possible that the CachingConnectionFactory is handling the exception and not passing it back to the flow?
To make it working you need to add the second Lambda to the .handle() with Jms:
.handle(Jms.outboundGateway(connectionFactory)
.receiveTimeout(45000)
.requestDestination("REQUEST_QUEUE")
.replyDestination("RESPONSE_QUEUE")
.correlationKey("JMSCorrelationID"),
e -> e.requiresReply(true))
By default AbstractReplyProducingMessageHandler doesn't require reply even if receiveTimeout is exhausted, and we see that by logs shown by you.
However, I see that we should revise all MessageHandlerSpecs, because XML support changes the requires-reply for some components to true by default.
Feel free to raise a JIRA issue on the matter and we'll address it soon, because the GA release for Java DSL is planned over a week or two: https://spring.io/blog/2014/10/31/spring-integration-java-dsl-1-0-rc1-released
Thank you for the attention to this stuff!

Resources