0

Here I'm using Scatter-gather pattern and calling 3 sub-flows parallelly. One of the flow (DBFlow) is taking lot's of time so gatherer is waiting for so long. I want the DB flow to happen but as that is a independent task so I don't want response back from DB Flow . I want only the other two flow's response and gather them. How to achieve that ?

//Configuration class

       @Configuration
    public class IntegrationConfiguration {
      @Autowired LoansServiceImpl loansService;
    
      long dbId = new SequenceGenerator().nextId();
      //   Main flow
      @Bean
      public IntegrationFlow flow() {
        return flow ->
            flow.split()
                .log()
                .channel(c -> c.executor(Executors.newCachedThreadPool()))
                .convert(LoanProvisionRequest.class)
                .scatterGather(
                    scatterer ->
                        scatterer
                            .applySequence(true)
                            .recipientFlow(flow1())
                            .recipientFlow(flow2())
                            .recipientFlow(flow3()),
                    gatherer -> gatherer.releaseLockBeforeSend(true))
                .log()
                .aggregate(a -> a.outputProcessor(MessageGroup::getMessages))
                .channel("output-flow");
      }
      //   flow1
      @Bean
      public IntegrationFlow flow1() {
        return integrationFlowDefination ->
            integrationFlowDefination
                .channel(c -> c.executor(Executors.newCachedThreadPool()))
                .handle(
                    message -> {
                      try {
                        lionService.saveLionRequest(
                            (LionRequest) message.getPayload(), String.valueOf(dbId));
                      } catch (JsonProcessingException e) {
                        throw new RuntimeException(e);
                      }
                    });
      }
    
      //   flow2
      @Bean
      public IntegrationFlow flow2() {
        return integrationFlowDefination ->
            integrationFlowDefination
                .channel(c -> c.executor(Executors.newCachedThreadPool()))
                .handle(
                    message ->
                        lionService.getData(
                            (LionRequest) message.getPayload(), SourceSystem.PROVISION))
                .log();
      }
    
      //  flow3
      @Bean
      public IntegrationFlow flow3() {
        return integrationFlowDefination ->
            integrationFlowDefination
                .channel(c -> c.executor(Executors.newCachedThreadPool()))
                .handle(
                    message ->
                        lionService.prepareCDRequest(
                            (LionRequest) message));
      }
    
      @Bean
      public MessageChannel replyChannel() {
        return MessageChannels.executor("output-flow", outputExecutor()).get();
      }
    
      @Bean
      public ThreadPoolTaskExecutor outputExecutor() {
        ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
        pool.setCorePoolSize(4);
        pool.setMaxPoolSize(4);
        return pool;
      }
    }

//Gateway service

@MessagingGateway
public interface LionGateway {

  @Gateway(requestChannel = "flow.input", replyChannel = "output-flow")
  List<?> echo(LionRequest lionRequest);
}

//Controller

  @Autowired private LionGateway lionGateway;

 @PostMapping(value = "/invoke-integration")
  public String invokeIntegrationFlow(@RequestBody LionRequest lionRequest) {
    String response = lionGateway.echo(lionRequest).toString();
    return response;
  }

1 Answers1

0

Add a custom release strategy to the gatherer.

/**
 * Strategy for determining when a group of messages reaches a state of
 * completion (i.e. can trip a barrier).
 */
@FunctionalInterface
public interface ReleaseStrategy {

    boolean canRelease(MessageGroup group);

}
gatherer -> gatherer.releaseLockBeforeSend(true)
                .releaseStrategy(msgGrp -> theOnesIWantHaveArrived(msgGrp))
                .discardChannel("nullChannel"));

It would be best to have the DB flow not return a reply, then you won't need the discard channel or any custom code.

Then, you could just use

gatherer -> gatherer.releaseLockBeforeSend(true)
                .releaseStrategy("size() == 2"));
Gary Russell
  • 166,535
  • 14
  • 146
  • 179
  • Thanks @Gary Russell. What exactly I need to write in theOnesIWantHaveArrived method? I mean how do I make sure that I don't want to receive reply from dbFlow? – Somnath Mukherjee Jun 29 '22 at 14:23
  • You would need to examine the replies. But, as I said, it's best to not have that flow return a value - you can always direct that result to `nullChannel` before it gets back to the gatherer. Just add `.nullChannel` to the end of that flow and use `size() == 2`. – Gary Russell Jun 29 '22 at 14:35
  • Okay @GaryRussel. – Somnath Mukherjee Jun 29 '22 at 16:46
  • if I use .nullChannel in the end of the dbFlow then only two responses will coming through then why do I have to explicitly mention size() == 2? – Somnath Mukherjee Jun 29 '22 at 17:26
  • Because you sent 3 requests and the default release strategy expects 3 replies. – Gary Russell Jun 29 '22 at 18:08