Scenario could be: my expectation could be 10 datapoint in batch, and I want to give response for {failed 5, pass 5} or sth.
my logic is to split the batch into data element and do validation.
successful validation will send to aggreagtor,
failed validation will throw error and pick up by error channel.
recipient-list-router take the errorChannel as inputChannel and 2 filter connect to it, the purpose is to filter some type of error to send response directly(eception unrelated to user input - server error or etc) and some type of client side error will go to aggregator to build response.
Is any problem with the logic? My problem is I keep getting "Reply message received but the receiving thread has already received a reply" when build up the Result using service-activator after aggregator. this service-activator connect to replyChannel and it seems like there are some message already sent to this channel?
I checked my integration work flow only this service-activator and server error branch after "error filter" connect to replyChannel(but the handle is never called.)
Something wrong? BTW, can recipient-list-router or other type of endpoint connect to errorChannel? or it has to be service-activator as what I saw in all the example online?(but they are really simple example..)
Sample XML
<int:gateway id="myGateway" service-interface="someGateway" default-request-channel="splitChannel" error-channel="errorChannel" default-reply-channel="replyChannel" async-executor="MyThreadPoolTaskExecutor"/>
<int:splitter input-channel="splitChannel" output-channel="transformChannel" method="split">
<bean class="Splitter" />
</int:splitter>
<int:transformer id="transformer" input-channel="transformChannel" method="transform" output-channel="aggregateChannel">
<bean class="Transformer"/> // this may throw the validation error (filter_ErrorType_1), if it cannot transform
</int:transformer>
<int:aggregator id="aggregator"
input-channel="aggregateChannel"
output-channel="createAnswerChannel"
method="aggregate">
<bean class="MyAggregator" />
</int:aggregator>
<int:recipient-list-router id="myErrorRouter" input-channel="errorChannel">
<int:recipient channel="filter_ErrorType_1"/>
<int:recipient channel="filter_ErrorType_2"/>
<int:recipient channel="filter_ErrorType_3"/>
</int:recipient-list-router>
<int:filter input-channel="filter_ErrorType_1" output-channel="aggregateChannel" method="accept"></int:filter>
<int:filter input-channel="filter_ErrorType_2" output-channel="createErrorAnswerChannel" method="accept"></int:filter>
<int:filter input-channel="filter_ErrorType_3" output-channel="createErrorAnswerChannel" method="accept"></int:filter>
<int:service-activator input-channel='createErrorAnswerChannel' output-channel="replyChannel" method='buildError'>
<bean class="AnswerBuilder"/>
</int:service-activator>
<int:service-activator input-channel='createAnswerChannel' output-channel="replyChannel" method='build'>
<bean class="AnswerBuilder"/>
</int:service-activator>
Follow up:
<int:gateway id="myGateway" service-interface="someGateway" default-request-channel="splitChannel" error-channel="errorChannel" default-reply-channel="replyChannel" async-executor="MyThreadPoolTaskExecutor"/>
<int:splitter input-channel="splitChannel" output-channel="transformChannel" method="split">
<bean class="Splitter" />
</int:splitter>
<int:transformer id="transformer1" input-channel="toTransformer1" method="transform" output-channel="toTransformer2">
<bean class="Transformer1"/> // this may throw the validation error (filter_ErrorType_1), if it cannot transform
</int:transformer>
<int:transformer id="transformer2" input-channel="toTransformer2" method="transform" output-channel="toTransformer3">
<bean class="Transformer2"/> // this may throw the validation error (filter_ErrorType_2), if it cannot transform
</int:transformer>
<int:transformer id="transformer3" input-channel="toTransformer3" method="transform" output-channel="aggregateChannel">
<bean class="Transformer3"/> // this may throw the validation error (filter_ErrorType_3), if it cannot transform
</int:transformer>
???
// seems like you are proposing to have one gateway for each endpoint that may throw error.
// but in this case, take transfomer 1 for example, I cannot output the gateway directly to aggregate channel since for valid data it has to go to transformer 2
// but the failed message throwed by the error handler cannot pass transformer 2 because of afterall this is a error message not a valid data for transformer 2
// <int:service-activator input-channel="toTransformer1" output-channel="toTransformer2" ref="gateway1"/>
// <int:gateway id="gateway1" default-request-channel="toTransformer1" error-channel="errorChannel1"/>
// <int:transformer id="transformer" input-channel="toTransformer1" method="transform">
// <bean class="Transformer"/> // this may throw the validation error (filter_ErrorType_1), if it cannot transform
// </int:transformer>
// how to deal with this problem?
<int:service-activator input-channel='createErrorAnswerChannel' output-channel="replyChannel" method='buildError'>
<bean class="AnswerBuilder"/>
</int:service-activator>
<int:service-activator input-channel='createAnswerChannel' output-channel="replyChannel" method='build'>
<bean class="AnswerBuilder"/>
</int:service-activator>
I actually have complicated logic inside but I use transformer 123 to represent here.