Spring JMS Outbound Gateway receive timeout being ignored - spring-integration

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!

Related

How do we check a message that caused a SessionLockLostException error in the service bus?

I am getting a few sessionlostlock exceptions while sending some messages to our SB triggered function app. We've set up alerts to check whenever such an error occurs. Although these messages do get retried and there no messages are sent to the DLQ. How do I find out which messages gave these exceptions in the first place.
How do I find out which messages gave these exceptions in the first place?
According to documentation:
You can use MessagingException.Detail Property to get the detail information on the messaging exception.
public Microsoft.ServiceBus.Messaging.MessagingExceptionDetail Detail { get; }
References: Cause and resolution of SessionLockLostException, Class SessionLockLostException and SessionLockLostException(String, Exception)

Spring Integration Jms.outboundGateway x Firewalls

This below flow is working fine when the network firewall is open, but if we close it and the JMS broker cannot be reached, the timeout is not happening at all and the caller process is getting stuck. It seems the gateway timer does not start because the thread did not return... Can you suggest what's the best way to handle this unhappy scenario?
#Bean
public IntegrationFlow request() {
return IntegrationFlows.from(requestChannel)
.handle(Jms.outboundGateway(this.connectionFactyory)
.requestDestination(requestQueue)
.extractReplyPayload(false)
.correlationKey("JMSCorrelationID")
.receiveTimeout(5000L))
.channel(replyChannel).get();
}
See receiveTimeout JavaDocs:
/**
* Set the max timeout value for the MessageConsumer's receive call when
* waiting for a reply. The default value is 5 seconds.
* #param receiveTimeout The receive timeout.
*/
public void setReceiveTimeout(long receiveTimeout) {
So, it is really about a reply, which is going to be triggered when we have already sent a request. More over you definitely use those default 5 seconds for its value. So, the blocking problem is somewhere else.
It would be great if you share with us some DEBUG (or even TRACE) logs for org.springframework.integration to see what is going on when you send a message to the flow without JMS broker access.

How to turn off automatic retry in Spring Integration Jms.inboundGateway

I am using
spring 4.2.4.RELEASE and
spring-integration-java-dsl:1.1.2.RELEASE
I have Jms.inboundGateway and some transformer. When transformer fails to transform a message, inbound gateway retries again and again. But I want to stop the entire flow in case of exception. Is it possible to do?
This is my flow configuration:
#Bean
public IntegrationFlow nonStop {
return IntegrationFlows
.from(Jms.inboundGateway(emsConnectionFactory)
.destination(myDestination)
.configureListenerContainer(spec -> spec
.sessionTransacted(true)
.subscriptionDurable(true)
.durableSubscriptionName(durableSubscriptionName)
.errorHandler((ErrorHandler) t -> {
t.printStackTrace();
throw new RuntimeException(t);
}))
.errorChannel(errorChannel)
.autoStartup(true)
.id(myNonStoppableFlow))
.filter(...)
.transform(...)
.handle(Jms.outboundAdapter(emsConnectionFactory)
.destination(myOnotherDestination))
.get();
}
One interesting notice. When errorHandler swallows an exception inbound gateway retires without any delay. When it throws Runtime exception there is delay about 5 seconds (which is not configured anywhere).
That retry in JMS is called like redelivery: http://www.javaworld.com/article/2074123/java-web-development/transaction-and-redelivery-in-jms.html.
So, any downstream exception makes for your message rollback and redelivery, which can be configured on Broker for the destination.
Actually if your .errorChannel(errorChannel) flow doesn't re-throw the exception, it will be treated as a successful handling and as commit.
From other side you should reconsider if you really need there a Jms.inboundGateway(). Because this one requires a reply, which doesn't look possible with your Jms.outboundAdapter() in the end.

How to handle timeout exception when using jms outbound gateway?

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.

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.

Resources