Spring integration:Header value router not getting invoked everytime - spring-integration

We are using header-value-router. Configuration:
<int:header-value-router input-channel="accountSummeryRequest"
header-name="word"
default-output-channel="accountSummeryRequest"
resolution-required="false">
<int:mapping value="xx" channel="accountSummeryRequest" />
<int:mapping value="yy" channel="newRequestChannel" />
</int:header-value-router>
<int:service-activator id="accountServiceActivator"
input-channel="accountSummeryRequest"
output-channel="accountSummeryResponse"
ref="serviceGatewayAdapter"
method="requestHandler"
send-timeout="60000"/>
<int:service-activator id="caRequestActivator"
input-channel="newRequestChannel"
output-channel="accountSummeryResponse"
ref="caServiceGatewayAdapter"
method="requestHandler"
send-timeout="60000"/>
now if i give word as yy,first time header-value-router enter code hereis getting called and exact service activator,in this case is caRequestActivator ,is called. But i try again with word=yy header-value-router is not getting called and request goes through accountServiceActivator. Alternate requests works correctly.
I don't know what's the problem here.

Your issue is around a round-robin dispatcher for accountSummeryRequest channel and its two subscribers: <int:header-value-router> and accountServiceActivator.
To fix it you should change the input-channel of that <service-activator> to some different channel. And, of course, don't fogtet to change the <header-value-router>
accordingly.

Related

AWS Async Response routing to success-channel for sqs-outbound-channel-adapter

I have registered an AsyncHandler and also added a success-channel to an SQS outbound flow. The success-channel has a int:logging-channel-adapter endpoint. However I am not able to see any logs from this adapter. The AsyncHandler is able to receive the call-backs but nothing on the success-channel.
In the SqsMessageHandler I see that we are setting an output channel in the obtainAsyncHandler method, but I did not see the success-channel set anywhere. Am I missing something?
I would prefer using the success and failure channels and not AsyncHandler call-back Impl to avoid having AWS specific code in my classes.
Also my <int-aws:sqs-outbound-channel-adapter> is inside a <int:chain> which has no output channel, since the flow ends when the message is sent.
EDIT - Added Config
This is the only way I can get it to log the callback.
<int:channel id="chainChannel" />
<int:channel id="successChannel" />
<bean class="ServiceTransformer" id="serviceTransformer" />
<int:chain input-channel="serviceChannel" id="sendToServiceSqsChain" output-channel="chainChannel">
<int:transformer ref="serviceTransformer" method="transform" />
<int:header-filter header-names="config" />
<int-aws:sqs-outbound-channel-adapter sqs="amazonSQS" queue="some-queue" async-handler="sqsPublishCallbackHandler" success-channel="successChannel"/>
</int:chain>
<int:logging-channel-adapter log-full-message="true" channel="chainChannel" />
Here I can just use the same channel in both chain (outbound channel) and sqs-outbound (success-channel)
Unable to get it to work like below:
<int:channel id="successChannel" />
<bean class="ServiceTransformer" id="serviceTransformer" />
<int:chain input-channel="serviceChannel" id="sendToServiceSqsChain" >
<int:transformer ref="serviceTransformer" method="transform" />
<int:header-filter header-names="config" />
<int-aws:sqs-outbound-channel-adapter sqs="amazonSQS" queue="some-queue" async-handler="sqsPublishCallbackHandler" success-channel="successChannel"/>
</int:chain>
<int:logging-channel-adapter log-full-message="true" channel="successChannel" />
The <int-aws:sqs-outbound-channel-adapter> component is one-way, therefore there is no outputChannel option expose. However the target class is AbstractMessageProducingHandler. To avoid code duplication we reuse an existing outputChannel internally for that AsyncHandler.
In the XML parser we just remap one to another:
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "success-channel", "outputChannel");
You probably don't see anything in logs because you need to adjust logging config respectively for the appropriate category and level.
UPDATE
According my testing this is definitely not possible to configure such a component with XML DSL within the <chain>. That <int-aws:sqs-outbound-channel-adapter> has to be presented outside of the <chain>.
Consider to more your configuration to Java DSL instead: https://docs.spring.io/spring-integration/docs/5.3.2.RELEASE/reference/html/dsl.html#java-dsl.

Understand how to clean store if we have exception between Splitter and Aggregator or recipient-list-router and Aggregator in Spring Integration

I am new to spring integration and we have created an SI flow where we have Splitter and Aggregator also recipient-list-router and Aggregator.
Today, while checking a code I got confused about how Aggregator will clean its store if we have an exception in between flow.
I am worried about the scenario where we got an exception between the flow and that creates stale state object in the system.
I have checked the spring integration doc but no luck (https://docs.spring.io/spring-integration/docs/2.0.0.RC1/reference/html/aggregator.html).
I can see only one topic "Managing State in an Aggregator: MessageGroupStore" but that is for "application shots down".
Also, I did google for the same and I found one thread https://dzone.com/articles/spring-integration-robust but not able to folow much. Sure, I will come back if I am able to find some solution.
I am using OOB Splitter, recipient-list-router and Aggregator. Considering pattern should have mechanism handle this common scenario.
Can you please guide me
i.e:
<int:recipient-list-router input-channel="inputChannel"
default-output-channel="nullChannel">
<int:recipient channel="aInputChannel" />
<int:recipient channel="bInputChannel" />
</int:recipient-list-router>
<int:service-activator ref="aHandler"
input-channel="aInputChannel" output-channel="aggregatorOutputChannel" />
<!-- we have exception in the bHandler -->
<int:service-activator ref="bHandler"
input-channel="bInputChannel" output-channel="aggregatorOutputChannel" />
<int:aggregator input-channel="aggregatorOutputChannel"
output-channel="outputChannel" />
OR
<int-file:splitter id="splitile"
charset="UTF-8" apply-sequence="true" iterator="false"
input-channel="inputChannel"
output-channel="bTransformerChannel" />
<!-- consider we have exception at 4th chunk -->
<int:service-activator ref="transform"
input-channel="bTransformerChannel" output-channel="aggregatorOutputChannel" />
<int:aggregator input-channel="aggregatorOutputChannel"
output-channel="outputChannel" />
Yes; the aggregator is a "passive" component by default - all actions are taken when a message arrives.
To time out stale groups you can use a reaper or, with more recent versions, a group-timeout.

How to define an exception router in chain after aggregator

I using Spring integration to aggregate messages into one and then send by FTP out bound adapter, I want to move the aggregated messages in a specific folder when outbound FTP server is not available(org.springframework.messaging.MessageDeliveryException), other exceptions will log by console.
Here is my Configuration
<int:chain id="transformChain" input-channel="inboundChannel">
<int:header-enricher>
<int:header name="file_name" expression="payload.name"/>
<int:header name="correlationId" expression="${header.enricher.correlationId}"/>
<int:header name="sum" expression="${header.enricher.sum}"/>
</int:header-enricher>
<int:transformer ref="fileNameToContentTransformer"/>
<int:aggregator send-partial-result-on-expiry="true"
release-strategy-expression="#this.size() == new Integer([0].headers.sum)"
group-timeout="${aggregator.group-timeout}"
message-store="messageStore"
expire-groups-upon-completion="true"
correlation-strategy-expression="headers.correlationId"/>
<int:transformer ref="xmlToJsonTransformer"/>
<ftp:outbound-channel-adapter remote-directory="${ftp.out.remote.directory}"
session-factory="ftpOutClientSessionFactory" auto-create-directory="true"
remote-filename-generator="fileNameGenerator" charset="UTF-8"
temporary-file-suffix=".writing">
</ftp:outbound-channel-adapter>
<int:exception-type-router >
<int:mapping exception-type="org.springframework.messaging.MessageDeliveryException" channel="undeliveredChannel"/>
<int:mapping exception-type="java.lang.Exception" channel="myErrorChannel"/>
</int:exception-type-router>
</int:chain>
However I met such exception when try to start.
Caused by: java.lang.IllegalArgumentException: All handlers except for the last one in the chain must implement the MessageProducer interface. Object of class [org.springframework.integration.ftp.outbound.FtpMessageHandler] must be an instance of interface org.springframework.integration.core.MessageProducer
at org.springframework.util.Assert.instanceCheckFailed(Assert.java:389)
at org.springframework.util.Assert.isInstanceOf(Assert.java:327)
at org.springframework.integration.handler.MessageHandlerChain.configureChain(MessageHandlerChain.java:119)
at org.springframework.integration.handler.MessageHandlerChain.onInit(MessageHandlerChain.java:99)
at org.springframework.integration.context.IntegrationObjectSupport.afterPropertiesSet(IntegrationObjectSupport.java:176)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1687)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624)
Anyone can tell me how to achieve this?
thanks in advance.
You can't add a component to the chain after the ftp:outbound-channel-adapter because it produces no result.
See the retry-and-more sample for an example of how to handle exceptions by adding an ExpressionEvaluatingRequestHandlerAdvice to the outbound adapter.

Spring Integration Chain Exception Handling with Header enricher inside chain

I have a common flow that will be reused multiple times. So, I defined a SI Chain for it like below.
<int:chain id="addInfo" input-channel="addInfoChannel">
<int:header-enricher>
<int:header name="outgoingService" value="Retrieve" />
</int:header-enricher>
<int:gateway request-channel="common_Retrieve_Channel" />
<int-xml:xslt-transformer xsl-templates="addInfoXslTemplate">
<int-xml:xslt-param name="param1" expression="headers.param1" />
<int-xml:xslt-param name="param2" expression="headers.param2" />
</int-xml:xslt-transformer>
<int:header-enricher>
<int:header name="outgoingService" value="Add" overwrite="true" />
</int:header-enricher>
<int:gateway request-channel="common_Add_Channel" />
</int:chain>
If the common_Retrieve_Channel channel fails with a SOAP fault, the header value (outgoingService) is lost.
If I have the header-enricher outside the chain, then header value is available on payload.failedMessage.headers.
I don't want to add this value outside chain, Since this value will be changing inside the chain to call another service.
This chain will be called multiple times by setting up the header values (param1 and param2) differently.
Please let me know if there is any better solution other than extracting the gateway into it's own chain. Thanks for your help.
You must have some compensation flow on the error-channel of your <gateway>.
Since you say that you have SOAP error and you already are familiar with the payload.failedMessage.headers you just need to write something like this there:
<int:transformer input-channel="gatewayErrorChannel" expression="payload.failedMessage"/>
And looks like you further <chain> flow should be the same. Only difference that you will get deal there with requestMessage only, but lose error information from the external SOAP request.

How to do parallelism in splitter-aggregator in spring integration?

I have a rest call to do inside splitter and then aggregate. I planned to implement parallelism for this rest call. So i introduced task executor as per this link. Now parallelism works but sometimes it is working and sometimes not. Guessing the aggregator is not waiting for all the thread to finish. Not sure exactly the problem. Can you help me here.
<int:enricher ipChann="som" opCahnnel="inputChannel" />
<int:splitter ipchan="inputChannel" opChannel="opchannel" ref="customersplitter" />
<int:channel id="opchannel" >
<int:dispatcher task-executor="exec" />
</int:channel>
<task:executor id="exec" pool-size="4" queue-capacity="10"/>
<int:enricher ipChannel="opchannel" opChannel="aggregatorChan"></int:enricher>
<int:aggregator ipChann="aggregatorChan" />
For simplicity i didnt expand enricher, but the flow are same.

Resources