exception scenario handling for input http headers in a REST api using spring integration - spring-integration

I need to do some validations on the input http headers, trying to write GET http rest api with some http headers, need to validate if one of the headers has specific value, if not throw an exception. I have used http inbound gateway, created error-channel and using service activator to notify error handler, I am getting below error,
No reply received from error channel within timeout
My code looks like,
<int-http:inbound-gateway
request-channel="sampleRequestChannel"
reply-channel="sampleResponseChannel"
error-channel="apiErrorChannel"
reply-timeout="15000"
supported-methods="GET"
path="/test/{testId}"
mapped-request-headers="*"
payload-expression="#pathVariables.testId">
<int-http:header name="source" expression="#requestParams[source]"/>
</int-http:inbound-gateway>
<int:service-activator input-channel="sampleRequestChannel" ref="testAdapterController" method="getDetails" output-channel="testSourceRouter"/>
<int:service-activator input-channel="apiErrorChannel" ref="testErrorHandler" method="handleFailedRequest" output-channel="sampleResponseChannel"/>
<bean id="loadErrorHandler" class="com.test.adapter.controller.TestErrorHandler"/>
<int:router input-channel="testSourceRouter" expression="headers.source">
<int:mapping value="ABCD" channel="callABCDChannel"/>
<!--<int:mapping value="std" channel="intermediateStdChannel"/>-->
</int:router>
I am throwing exception in the code but its not reaching to the output channel even though I tried using output channel as reply channel.
I can see exception being thrown in my console logs but api doesn't throw it as a part of api response. I am pretty sure my understanding of working with spring integration is very limited, just started to work with it.
could someone please help?

To re-throw an exception to MVC there is just enough to not have that error-channel="apiErrorChannel" configured.
If you'd like to swallow it and return something else, then your testErrorHandler must return that object.
This is going to work as is if all your channels in the flow are DirectChannel which is a default type. If it is not, then you must look into this section of the doc and ensure an errorChannel downstream as a header: https://docs.spring.io/spring-integration/docs/current/reference/html/error-handling.html#error-handling

Related

http retry advice not retrying when an exception is thrown

I have service activator method which throws database exception, I am catching that exception and sending ResponseEntity to the output channel. I have retry advice configured on the service activator but its doesn't retry(I am assuming its because I am catching it and sending custom exception to the output channel), I want it to retry 4 times first and then send custom exception. can you please how can I achieve it?
<int:chain id="a1-chain" input-channel="dRequestInputChannel" output-channel="dIntermediateChannel">
<int:service-activator ref="dAdapterController" method="dPersist">
<int:request-handler-advice-chain>
<int:retry-advice max-attempts="4" recovery-channel="dRetryChannel">
<int:exponential-back-off initial="1000" multiplier="5.0" maximum="60000" />
</int:retry-advice>
</int:request-handler-advice-chain>
</int:service-activator>
</int:chain>
<int:transformer input-channel="dRetryChannel" expression="payload.getFailedMessage()"/>
There is some piece of code after this in which I have a chain which has input channel as dIntermediateChannel and one router etc. which works fine! I meant to say flow works fine without retrying!
You said it yourself:
I am catching that exception and sending ResponseEntity to the output channel.
It is not clear what made you think that retry has to work in this case: if not exception is thrown from the user code, then nothing to catch in the retry interceptor and therefore no trigger to initiate retry policy.
Please, don't confuse yourself and us. We don't know what is your code, but your say:
then send custom exception
So, send it is a part of ResponseEntity or throw?
I would say in the first case it is just custom reply and doesn't matter what is its body. As long as it does not cause throws it is not an exception to catch.
If you want a retry and then fallback, so take a look into a logic where you don't catch exception yourself, but let it to be done by the retry-advice.
To make a custom reply, you need to look into a RecoveryCallback injected into a RequestHandlerRetryAdvice. Unfortunately, that int:retry-advice does not expose RecoveryCallback. An existing recovery-channel does not expect a reply to be produced from the publishing.
Another way is to use an ExpressionEvaluatingRequestHandlerAdvice around this retry to catch the final exception and produce some compensation.

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).

Why is exception is not thrown to the error-channel of the inbound when claim-check is used

In the error-channel attribute of message-driven-channel-adapter
I want the original inbound message as the payload not the payload at the point of failure. To achieve this I use claim-check-in/out and SimpleMessageStore. The UUID I get from claim-check-in is stored in the header of the original inbound message. This message is now consumed by the transformer and then webservice call.
When the service time out or transformation exception is thrown the error-channel of message-driven-channel-adapter does not get any message, also it seems to retry in its own infinite loop rather than throwing an exception to error-channel. Is this the expected behaviour, Please let me know if I am missing something.

Spring Integration Http Inbound Gateway Request Logging

Hi I am currently using Spring Integration 4.0.3.I have a requirement of logging the actual request which are coming to the Http Inbound Gateways.The request are to be logged before they are converted into a message by the Http Inbound Messaging Gateway and sent to the gateway request channel.This is how I am trying to achieve this .
Configured a aop pointcut on the HttpRequestHandlingMessagingGateway class handleRequest method.
Configured a custom method Interceptor as an advice and configured the pointcut to execute this advice in the aop config.
In the MethodInterceptor I am retreiving the Request and Response object and logging the request.
But it seems whenever I am applying the aop on handleRequest method the dispatcher servlet is unable to find the handler for any of the url mapping used by all of my http inbound gateways.
I know the same can be achieved through configuring filters in web.xml but I am just curious why this is happening....Please help ...
Actually you can't proxy HttpRequestHandlingMessagingGateway#handleRequest because it is final.
From other side there is no reason to do so complex AOP work for that logging stuff.
HttpRequestHandlingMessagingGateway populates RequestContextHolder.currentRequestAttributes() as EvaluatationContext variable, so you can put it to MessageHeader and use anywhere in downstream flow:
<int-http:inbound-gateway path="/foo" request-channel="requestChannel">
<int-http:header name="requestAttributes" expression="#requestAttributes"/>
</int-http:inbound-gateway>
<publish-subscribe-channel id="requestChannel"/>
<logging-channel-adapter channel="requestChannel"
expression="headers.requestAttributes.request"/>

How to acknowledge message through program using Spring AMQP/Spring integration

1) Server sends a message to client.
2) Inbound channel adapter is configured to wait for "MANUAL" acknowledge mode operation from consumer
3) "TaskBundlereceiver" bean is implementing "ChannelAwareMessageListener" and in the implementation method, I am performing message acknowledgement.
I don't see "TaskBundlereceiver" getting executed. Am I missing something ?
Below is the configuration details of the steps that I have explained.
Appreciate your inputs.
#Override
public void onMessage(org.springframework.amqp.core.Message message, Channel channel) throws Exception
{
logger.debug("In onMessage method of the channel aware listener. message =["+message.getBody().toString()+"]");
channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
}
XML Configuration :
<!-- Channel that receives the task bundle from the server for execution -->
<int:channel id="fromKServerChannel"/>
<int-amqp:inbound-channel-adapter id="taskBundleReceiverAdapter"
channel="fromKServerChannel"
error-channel="taskBundleErrorChannel"
acknowledge-mode="MANUAL"
expose-listener-channel="true"
queue-names="kanga_task_queue"
connection-factory="connectionFactory"
concurrent-consumers="20"/>
<int:chain input-channel="fromKServerChannel" output-channel="nullChannel">
<int:service-activator ref="taskBundleReceiver" method="onMessage"/>
<int:service-activator ref="taskBundleExecutor" method="executeBundle"/>
</int:chain>
It doesn't work that way; the listener is the adapter, not the service invoked via the service-activator. The adapter currently does not support passing the channel to the client for manual acks. The expose-listener-channel attribute is for use when using transactions, so a down-stack rabbit template can participate in the transaction.
Why do you want MANUAL acks? AUTO (default) means the ack will be done automatically by the container when the thread returns normally; if your service throws an exception, the message will be nacked.
So, that's how to control the ack.
If you really want to use MANUAL acks, you'll have to use a <rabbit:listener-container/> to invoke your taskBundleReceiver directly. It could then send a message to the executor using a messaging gateway.

Resources