简体   繁体   中英

How to handle http response exception and continue the flow till aggregate in Spring integration

I'm using Spring-integration in my project and the pattern used is scatter-gather. Here three parallel processes are being carried out. The flow2 is a outbound gateway method and if that service is down then I want to handle the Httpstatus exception and want to send null. Actually if that service is down then the whole flow is getting stopped. But I want to handle that exception and send null and then want to continue with the aggregate method and end the flow.

Below is the code - -

//Config file

 @Configuration
        public class IntegrationConfiguration {
          @Autowired LionsServiceImpl lionsService;
        
          long dbId = new SequenceGenerator().nextId();
      //   Main flow
      @Bean
  public IntegrationFlow flow() {
    return flow ->
        flow.handle(validatorService, "validateRequest")
            .split()
            .channel(c -> c.executor(Executors.newCachedThreadPool()))
            .scatterGather(
                scatterer ->
                    scatterer
                        .applySequence(true)
                        .recipientFlow(flow1())
                        .recipientFlow(flow2())
                        .recipientFlow(flow3()),
                gatherer ->
                    gatherer
                        .releaseLockBeforeSend(true)
                        .releaseStrategy(group -> group.size() == 2))
            .aggregate(prepareSomeRequest())
            .to(getDec());
  }

  //   Saving the request to the database
  @Bean
  public IntegrationFlow flow1() {
    return integrationFlowDefinition ->
        integrationFlowDefinition
            .channel(c -> c.executor(Executors.newCachedThreadPool()))
            .handle(
                (payload, header) -> {
                  ObjectMapper mapper = new ObjectMapper();
                  try {
                    String jsonString = mapper.writeValueAsString(payload);
                    JsonNode request = mapper.readTree(jsonString);
                    JsonNode csID = request.get("ApplicationDetails").get("CustomerId");
                    int customerID = mapper.treeToValue(csID, Integer.class);

                    return lionService.saveRequest(
                        payload,
                        String.valueOf(dbId),
                        customerID,
                        ((SourceSystem) Objects.requireNonNull(header.get("sourceSystem")))
                            .getSourceSystemCode());
                  } catch (JsonProcessingException e) {
                    throw new RuntimeException(e);
                  }
                }
                )
            .nullChannel();
  }

  // 
  @Bean
  public IntegrationFlow flow3() {
    return integrationFlowDefinition ->
        integrationFlowDefinition
            .channel(c -> c.executor(Executors.newCachedThreadPool()))
            .transform(
                message ->
                    loansService.someMethod(
                        (LionRequest) message));
  }

 //Here I'm calling a service through HTTPOUTBOUNDGATEWAY and if that called service is down then it throws HTTP STAtus error so I want to handle that and want to send null from this flow.
  @Bean
  public IntegrationFlow flow2() {
    return integrationFlowDefinition ->
        integrationFlowDefinition
            .channel(c -> c.executor(Executors.newCachedThreadPool()))
            .handle(
                (payload, header) ->
                    loansService.someMethod2(
                        (LionRequest) payload,
                        (SourceSystem) (Objects.requireNonNull(header.get("sourceSystem")))))
            .handle(
                Http.outboundGateway(someurl)
                    .httpMethod(HttpMethod.POST)
                    .expectedResponseType(String.class)
                       );
  }


  @Bean
  public IntegrationFlow getDec() {
    return flow ->
        flow.handle(
            Http.outboundGateway(ServiceURL)
                .httpMethod(HttpMethod.POST)
                .expectedResponseType(CrResponse.class));
  }


  @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;
  }


//here I want to take out null from messages which is sent by flow2 if the called service is down and then I want to send null to someMethod2 method.

  public MessageGroupProcessor prepareSomeRequest() {
    return group -> {
      String cData;
      Object CDReq;

      List<Message<?>> messages = group.streamMessages().collect(Collectors.toList());

      ArrayList<Object> payloads = (ArrayList<Object>) messages.get(0).getPayload();

      if (payloads.get(0).toString().contains("tribv")) {
        cData= payloads.get(0).toString();
        logger.atInfo().log("Customer data from Data Sourcing Service : " + cData);
        CDReq= payloads.get(1);
      } else {
        cData= payloads.get(1).toString();
        logger.atInfo().log("Customer data from Data Sourcing Service : " + cData);
        CDReq = payloads.get(0);
      }

      Object fReq =
          lionservice.someMethod2(cData, CDReq);

      SomeRequest somreq= new SomeRequest();

      ObjectMapper mapper = new ObjectMapper();

      JsonNode req = mapper.valueToTree(freq);
      creditDecisionRequest.setfsfgg(req);
      creditDecisionRequest.setR("234565432");
      creditDecisionRequest.setD(String.valueOf(dbId));
      creditDecisionRequest.setCID("33333333");
      creditDecisionRequest.setSourceSystemCode(SourceSystem.ONE.getSourceSystemCode());

      return somreq;
    };
  }

Gateway

    @Gateway(requestChannel = "flow.input")
  void processLionRequest(
      @Payload Message lionRequest, @Header("sourceSystem") SourceSystem sourceSystem);

Can I use something like .errorHandler() in the outboundgateway? But how do I use that?

 @Bean
  public IntegrationFlow flow2() {
    return integrationFlowDefinition ->
        integrationFlowDefinition
            .channel(c -> c.executor(Executors.newCachedThreadPool()))
            .handle(
                (payload, header) ->
                    lionService.prepareSomeRequest(
                        (LionRequest) payload,
                        (SourceSystem) (Objects.requireNonNull(header.get("sourceSystem")))))
            .handle(
                Http.outboundGateway(someurl)
                    .httpMethod(HttpMethod.POST)
                    .expectedResponseType(String.class),
                c -> c.advice(expressionAdvice()));
  }

  @Bean
  public Advice expressionAdvice() {
    ExpressionEvaluatingRequestHandlerAdvice advice =
        new ExpressionEvaluatingRequestHandlerAdvice();
    advice.setFailureChannelName("failure.input");
    advice.setTrapException(true);
    return advice;
  }

  @Bean
  public IntegrationFlow success() {
    return f -> f.handle(System.out::println);
  }

  @Bean
  public IntegrationFlow failure() {
    return f -> f.handle(adviceOnFailure());
  }

  public String adviceOnFailure() {
    return "Failed";
  }

I'm doing something like that but getting error as below -

Caused by: java.lang.IllegalArgumentException: Found ambiguous parameter type [class java.lang.String] for method match: [public byte[] java.lang.String.getBytes(java.nio.charset.Charset), public static java.lang.String java.lang.String.valueOf(double), public boolean java.lang.String.contains(java.lang.CharSequence), public static java.lang.String java.lang.String.copyValueOf(char[]), public java.lang.String[] java.lang.String.split(java.lang.String), public native java.lang.String java.lang.String.intern(), public java.lang.String java.lang.String.repeat(int), public static java.lang.String java.lang.String.valueOf(char), public static java.lang.String java.lang.String.valueOf(boolean), public static java.lang.String java.lang.String.valueOf(java.lang.Object), public static java.lang.String java.lang.String.valueOf(float), public static java.lang.String java.lang.String.valueOf(long), public java.lang.String java.lang.String.toUpperCase(java.util.Locale), public boolean java.lang.String.contentEquals(java.lang.StringBuffer)]

please help.

There is no null payload concept in messaging, so even if you handle an error, you definitely cannot return null as a reply from that Outbound Gateway call.

See Request Handler Advice pattern in the framework, in particular an ExpressionEvaluatingRequestHandlerAdvice implementation. It does handle error for the specific message handler and may return a compensation reply which you then can aggregator and process respectively.

The doc is here: https://docs.spring.io/spring-integration/docs/current/reference/html/messaging-endpoints.html#message-handler-advice-chain

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM