1

How to resend same or modified message from outbound http call in case of specific client error responses like 400, 413 etc

@Bean
private IntegrationFlow myChannel() {
    IntegrationFlowBuilder builder = 
             IntegrationFlows.from(queue)
              .handle(//http post method config)
                    ...
                  .expectedResponseType(String.class))
              .channel(MessageChannels.publishSubscribe(channel2));
   return builder.get();
}

@Bean
private IntegrationFlow defaultErrorChannel() {
    
}

EDIT: Added end point to handle method

@Bean
private IntegrationFlow myChannel() {
    IntegrationFlowBuilder builder = 
             IntegrationFlows.from(queue)
              .handle(//http post method config)
                    ...
                  .expectedResponseType(String.class), 
                               e -> e.advice(myRetryAdvice()))
              .channel(MessageChannels.publishSubscribe(channel2));
   return builder.get();
}

@Bean
public Advice myRetryAdvice(){
 ... // set custom retry policy
}

Custom Retry policy:

class InternalServerExceptionClassifierRetryPolicy extends 
      ExceptionClassifierRetryPolicy {
    public InternalServerExceptionClassifierRetryPolicy() {
       final SimpleRetryPolicy simpleRetryPolicy = 
                  new SimpleRetryPolicy();
    simpleRetryPolicy.setMaxAttempts(2);

    this.setExceptionClassifier(new Classifier<Throwable, RetryPolicy>() {
        @Override
        public RetryPolicy classify(Throwable classifiable) {
            if (classifiable instanceof HttpServerErrorException) {
                // For specifically 500 and 504
                if (((HttpServerErrorException) classifiable).getStatusCode() == HttpStatus.INTERNAL_SERVER_ERROR
                        || ((HttpServerErrorException) classifiable)
                                .getStatusCode() == HttpStatus.GATEWAY_TIMEOUT) {
                    return simpleRetryPolicy;
                }
                return new NeverRetryPolicy();
            }
            return new NeverRetryPolicy();
        }
    }); 
}}

EDIT 2: Override open() to modify the original message

    RequestHandlerRetryAdvice retryAdvice = new 
    RequestHandlerRetryAdvice(){
    @Override
    public<T, E extends Throwable> boolean open(RetryContext 
    retryContext, RetryCallback<T,E> callback){
    Message<String> originalMsg = 
(Message)  retryContext.getAttribute(ErrorMessageUtils.FAILED_MESSAGE_CONTEXT); 
   Message<String> updatedMsg = //some updated message

retryContext.setAttribute(ErrorMessageUtils.FAILED_MESSAGE_CONTEXT,up datedMsg); return super.open(retryContext, callback); }

starball
  • 20,030
  • 7
  • 43
  • 238
sophopile
  • 11
  • 2

1 Answers1

0

See a RequestHandlerRetryAdvice: https://docs.spring.io/spring-integration/reference/html/messaging-endpoints.html#message-handler-advice-chain. So, you configure some RetryPolicy to check those HttpClientErrorException for retry and the framework will re-send for you.

Java DSL allows us to configure it via second handle() argument - endpoint configurer: .handle(..., e -> e.advice(myRetryAdvice)): https://docs.spring.io/spring-integration/reference/html/dsl.html#java-dsl-endpoints

Artem Bilan
  • 113,505
  • 11
  • 91
  • 118
  • Thanks a lot Artem. I’ll try to follow the suggestions and get back. – sophopile Jan 17 '23 at 19:53
  • Hi @ArtemBilan, I followed your suggestion and created a Retry policy (see EDIT). The solution works. But not sure if this would help my scenario to modify the original message before the retry. Retry policy : https://stackoverflow.com/questions/27236216/is-it-possible-to-set-retrypolicy-in-spring-retry-based-on-httpstatus-status-cod – sophopile Jan 20 '23 at 18:28
  • The `RequestHandlerRetryAdvice` implements a `RetryListener` and its `open()` impl it sets a `message` in retry into context under `ErrorMessageUtils.FAILED_MESSAGE_CONTEXT_KEY` key. So, in your `RetryPolicy` impl you really got access to your message to modify. Although bear in mind that it is possible only for mutable headers. You can of course try to send to your `handle()` a `MutableMessage`, but there might be a case when it is rebuilt internally before it reaches an advice. – Artem Bilan Jan 20 '23 at 19:32
  • Hello Artem, thanks for the suggesting on the open(). I updated the code to override the open method (EDIT 2above). But I am not able to find RetryContext object and getting error for the same. – sophopile Jan 22 '23 at 03:47
  • No, that's not what I meant. See that `open()` JavaDocs. It is called only once in the beginning of retry. And yes, that one in the `RequestHandlerRetryAdvice` adds respective `ErrorMessageUtils.FAILED_MESSAGE_CONTEXT_KEY` entry to the `RetryContext`. This one you can access from your `RetryPolicy.canRetry()` and modify respectively. – Artem Bilan Jan 23 '23 at 13:59
  • I am sorry but could you please elaborate. What I am not able to understand is how to get RetryContext. The canRetry(RetryContext context) also needs the RetryContext. – sophopile Jan 23 '23 at 18:54
  • Not sure what you mean. You implement (or override) a `RetryPolicy.canRetry()`. The framework calls this method with respective `RetryContext` and after that `open()` implementation (default) in the `RequestHandlerRetryAdvice` this context is going to have an `ErrorMessageUtils.FAILED_MESSAGE_CONTEXT_KEY` entry. – Artem Bilan Jan 23 '23 at 18:58