0

I'm using Spring-integration java dsl in my project and I want to add configurable timeout for the parallel services that are being called. I should be able to add different timeout for thr different flows that I'm using here. Kindly help me with this.

Below is the codebase :

Config file

@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

 @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 response1 = lionGateway.echo(lionRequest).get(0);
    String response2 = lionGateway.echo(lionRequest).get(1);
    System.out.Println("response2 ")
    System.out.Println("response1 ")

    return "response";
  }

1 Answers1

0

It is not clear what that timeout should be and where. But if you are OK with our speculations, here is one of the options:

.recipientFlow(f1 -> f1.gateway(flow1(), gateway -> gateway.replyTimeout(2000L)))

The replyTimeout also can be very dynamic and based on the request message: just set a receiveTimeout header, respectively!

Otherwise, please, elaborate.

Artem Bilan
  • 113,505
  • 11
  • 91
  • 118
  • Hi @Artem, thanks for the response. If u see I have 3 recipients flows and for each flows I want to set timeout so that if I will only wait for that much time to get the response back. for example let's suppose any of my flow is a http call I want to wait for certain amount of time. That only I want configure here. Hope this explains. – Somnath Mukherjee Jul 06 '22 at 16:04
  • Configure where? The timeout makes sense in messaging only when we perform a request-reply, like the `gateway` I explain in my answer. Why this is not enough for you? Of course there is a `replyTimeout` feature in HTTP client and so on. Therefore, please, elaborate where exactly you'd like to timeout and why a suggested approach with gateway on each recipient does not work for you. – Artem Bilan Jul 06 '22 at 16:12
  • Actually I applied your approach, in that case it's still waiting for the response from the http call, though timeout is being applied but still it's receiving message. Asu can see from the log -2022-07-06T21:59:24,630WARN [pool-14-thread-2]org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel:Reply message received but the receiving thread has exited due to a timeout: GenericMessage [payload={"TRIADInputData":{"CDTScoring":[{"AlignedScore":0,"ExclusionCat":"","Rawscore":0,",.....}] . Actually I want it to wait for the given timeout time and then existing. – Somnath Mukherjee Jul 06 '22 at 16:31
  • Also one more thing when I hit the controller from postman which intern fire the Integration flow, is not giving response, if I apply the timeout. It's keep on waiting. Generally gatherer should gather the result and give me back even if I don't get the response back from one of the flow due to late response. – Somnath Mukherjee Jul 06 '22 at 16:37
  • That's not how async algorithms work. You wait on the barrier and exit: it is already out of your barrier control how the underlying process works. It is just abandoned, but that doesn't mean that you can interrupt it. You just can ignore that warning in logs. You probably is just confused a bit: even if that reply comes back, it happens far away from your original call. It is a late reply and doesn't not affect the rest of your logic. – Artem Bilan Jul 06 '22 at 16:38
  • The response back from the scatter-gather depends on the grouping algorithm you apply for the gatherer part. Right now you have just this: `gatherer -> gatherer.releaseLockBeforeSend(true))`, which means wait for replies from all the recipients and only after that build a reply message. Not sure why do you expect anything else if you don't receive all the replies. See docs on the matter: https://docs.spring.io/spring-integration/docs/current/reference/html/message-routing.html#scatter-gather-functionality – Artem Bilan Jul 06 '22 at 16:42
  • Okay, sorry if I'm asking basic question. Just wanted to know if one of my flow is not giving response back due to late response then if I remove gatherer -> gatherer.releaseLockBeforeSend(true)) , then will I be able to gather only the other flows responses and print it in the controller ? Actually when I'm hitting the controller as one of the flow is not giving response back so no response is coming back in the end of the actual main flow. If u see I'm taking the response back from the reply channel returning as response. But here it's not giving any response back though in log it's showing. – Somnath Mukherjee Jul 06 '22 at 17:34
  • I mean here in the controller I'm just returning a string but in my actual code I'm returning whatever is coming back from liongateway.echo(lionRequest). – Somnath Mukherjee Jul 06 '22 at 17:36
  • That's not correct. By default the aggregator waits for all the splitted messages. See the doc I pointing in one of my previous comments. Your aggregation logic is custom. Therefore you have to configure respective `releaseStrategy` – Artem Bilan Jul 06 '22 at 17:36
  • You send 3 messages at the moment, so default aggregator waits for 3 replies. Since you say it is OK with you to timeout, then it means you are not going to have all the 3 replies. Please, learn what is `releaseStrategy` and how to achieve a custom algorithm with an aggregator. For example you can utilize a `groupTimeout` approach... – Artem Bilan Jul 06 '22 at 17:38
  • Actually didn't find proper examples on releaseStrategy in net. Artem, now gatherer wait for the responses to come back from all the flows, so when timeOut comes into play no response is being sent. But whenever timeOut comes into play(means within the given time the flow doesn't give response back), I want to throw my custom exception as response back, then I want to terminate the call. Is it possible? – Somnath Mukherjee Jul 10 '22 at 11:50