I'm trying to find reason of different behavior between Executor Channel and Direct Channel in java app with Spring Integration framework.
I want to check failover flow and be sure that messages are not being duplicated - for both cases JmsOutboundGateway -> secondGateway will always throw error.
First scenario
inputLocalChannel - Executor Channel
inputGateway - Direct Channel
inputGatewayBck - Direct Channel ( secondGateway - failing flow )
I don't know why but messages are duplicated - I sent only 3 messages but on response queue there are 6
Second scenario
inputLocalChannel - Executor Channel
inputGateway - Executor Channel
inputGatewayBck - Executor Channel ( secondGateway - failing flow )
In this case I send 3 message and receive 3 - and this is as expected.
@MessagingGateway(name = "LocalGateway")
public interface LocalGateway {
@Gateway(requestChannel = "inputLocalChannel")
ListenableFuture<Message<String>> sendMsg(Message<String> request);
}
@Bean
@ServiceActivator(inputChannel = "inputLocalChannel")
public Message<String>firstHandler(){
// some code
}
@Bean
@ServiceActivator(inputChannel = "inputLocalChannel")
public Message<String> secondHandler(){
// some code
}
@Bean
@ServiceActivator(inputChannel = "inputGateway")
public JmsOutboundGateway firstGateway(){
// some code
}
@Bean
@ServiceActivator(inputChannel = "inputGatewayBck")
public JmsOutboundGateway secondGateway(){
// some code
}
Is there a possibility to use same thread in channel flow inputLocalChannel -> inputGateway inputLocalChannel -> inputGatewayBck
without context switching ? And why in case of using Direct Channel those messages are duplicated ?
The
DirectChannelcomes with a round-robin strategy by default. So, since you have two subscribers for thatinputLocalChannelyou end up with the situation when the first message is handled by the first subscriber, second by the second one and so on looping between those subscriber on each message.Now about errors. That channel uses a
UnicastingDispatcherwith afailover = trueby default. And the logic is like this: if the currentMessageHandlerfails, the same message is handed to the next subscriber.Not sure if that is expected, but probably you would prefer to set
LoadBalancingStrategyas null into that channel, so no round-robin would happen, but failover on the error in theMessageHandlerwould still be in action.The difference with an
ExecutorChannelfor thatinputGatewaythat exception which happened in the subscriber for this channel is not bubbled up to the caller. Therefore that failover has no way to know that it has to iterate to the next subscriber. Just because all the stuff happens on a different thread and therefore error handling must be done differently: https://docs.spring.io/spring-integration/reference/error-handling.html