Clawdidr
Clawdidr

Reputation: 616

Change parameter values on each Spring Retry attempt

I have following method which is @Retryable:

    @Retryable(value = HttpClientErrorException.class)
    public Integer callToExternalService(DateTime start, DateTime end) throws MyException

My question is if I can modify input parameters each time method is under retry because I need to make a rest call with different values. Is there an option similar to @Recover for this case?

Upvotes: 6

Views: 3075

Answers (1)

Gary Russell
Gary Russell

Reputation: 174564

Not out of the box; you would need to add another advice closer to the bean than the retry interceptor to modify the MethodInvocation.arguments.

Or you could subclass the retry interceptor and override the invoke method.

Neither one is trivial, unless you have some knowledge about Spring proxies.

Here's a simpler way to do it; it will need a bit more work if you need to recover rather than throw the last exception to the caller.

@SpringBootApplication
@EnableRetry
public class So61486701Application {

    public static void main(String[] args) {
        SpringApplication.run(So61486701Application.class, args);
    }

    @Bean
    MethodInterceptor argumentChanger() {
        RetryTemplate retryTemplate = new RetryTemplate();
        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(3);
        FixedBackOffPolicy backOff = new FixedBackOffPolicy();
        backOff.setBackOffPeriod(1000L);
        retryTemplate.setRetryPolicy(retryPolicy);
        retryTemplate.setBackOffPolicy(backOff);
        return invocation -> {
            return retryTemplate.execute(context -> {
                if (context.getRetryCount() > 0) {
                    Object[] args = invocation.getArguments();
                    args[0] = ((Integer) args[0]) + 1;
                    args[1] = ((String) args[1]) + ((String) args[1]);
                }
                return invocation.proceed();
            });
        };
    }


    @Bean
    public ApplicationRunner runner(Foo foo) {
        return args -> foo.test(1, "foo.");
    }

}

@Component
class Foo {

     @Retryable(interceptor = "argumentChanger")
     public void test(int val, String str) {
        System.out.println(val + ":" + str);
        throw new RuntimeException();
     }

 }

Upvotes: 3

Related Questions