0

I am facing error in adding a custom BackOffPolicy to spring-retry I followed the approach from Incremental linear backoff in Spring Retry .

My Retryable method is

    @Autowired
    private RetryOperationsInterceptor retryOperationsInterceptor;

    @Override
    @Retryable(
            interceptor = "retryOperationsInterceptor",
            maxAttemptsExpression = "#{${customer.maxRetries:8}}",
              value=Exception.class
            )
    public customer getcustomer(String abc) { 
        LOGGER.info("Trying to fetch customer details.");
     }
    @Recover
    public customer recover(RuntimeException e, String abc){
        LOGGER.info("Recovering - returning safe value");
        return null;
    }

My configuration file is

    @EnableRetry
    public class RetryConfigurations {

    @Autowired
    private LinearBackoffPolicy linearBackoffPolicy;

    @Bean(name = "retryOperationsInterceptor")
    RetryOperationsInterceptor retryOperationsInterceptor() {
        return RetryInterceptorBuilder.stateless().backOffPolicy(linearBackoffPolicy).build();
    }

I defined a simple linearBackOffPolicy as

package com.ncr.digitalbanking.prism.connector.configuration;

import org.springframework.retry.backoff.BackOffInterruptedException;
import org.springframework.retry.backoff.Sleeper;
import org.springframework.retry.backoff.SleepingBackOffPolicy;
import org.springframework.retry.backoff.StatelessBackOffPolicy;
import org.springframework.retry.backoff.ThreadWaitSleeper;
import org.springframework.stereotype.Component;

@Component
public class LinearBackoffPolicy extends StatelessBackOffPolicy implements SleepingBackOffPolicy<LinearBackoffPolicy>{

    private static final long DEFAULT_BACK_OFF_PERIOD = 1000L;

    private volatile long backOffPeriod = DEFAULT_BACK_OFF_PERIOD;

    private volatile long backOffDelta = DEFAULT_BACK_OFF_PERIOD;

    private Sleeper sleeper = new ThreadWaitSleeper();

    public LinearBackoffPolicy withSleeper(Sleeper sleeper) {
        LinearBackoffPolicy linearBackoffPolicy = new LinearBackoffPolicy();
        linearBackoffPolicy.setBackOffPeriod(backOffPeriod);
        linearBackoffPolicy.setSleeper(sleeper);
        return linearBackoffPolicy;
    }

    public long getBackOffPeriod() {
        return backOffPeriod;
    }

    public void setBackOffPeriod(long backOffPeriod) {
        this.backOffPeriod = (backOffPeriod > 0? backOffPeriod : 500);
    }

    public void setSleeper(Sleeper sleeper) {
        this.sleeper = sleeper;
    }

    protected void doBackOff() throws BackOffInterruptedException {
        try {
            sleeper.sleep(backOffPeriod);
            backOffPeriod = backOffPeriod + backOffDelta;
        }
        catch (InterruptedException e) {
            throw new BackOffInterruptedException("Thread interrupted while sleeping", e);
        }
    }

    public String toString() {
        return "LinearBackoffPolicy [backOffPeriod=" + backOffPeriod + "]";
    }
}

Problems Unable to use linear backoff policy in the rest call. Unable to invoke Recover method after all retry attempt fails. Note My project works fine with this configuration

@Retryable(
            interceptor = "retryOperationsInterceptor",
            maxAttemptsExpression = "#{${prism.cas.maxRetries:8}}",
              value=Exception.class
              backoff = @Backoff(
                delayExpression  = "#{${prism.cas.delayExpression:10000}}",
                multiplier = 2,
                maxDelay = 12000
              )
            )

Did I mess up something?

1 Answers1

0

@Recover doesn't work with a manually configured interceptor; it only works when the framework builds the interceptor.

You need to add .recoverer(...) to your interceptor builder.

Also

    /**
     * Retry interceptor bean name to be applied for retryable method. Is mutually
     * exclusive with other attributes.
     * @return the retry interceptor bean name
     */
    String interceptor() default "";

your maxAttemptsExpression is ignored; the max attempts also has to go on the builder.

Gary Russell
  • 166,535
  • 14
  • 146
  • 179
  • Hi Garry, Thanks for the help, now I can add both recoverer and maxAttemptsExpression but I have another situation. I cant limit on the error class. If I want that then I think I need to add in RetryTemplate and provide my BackOffPolicy to it. Correct me if I am wrong. – Shiv Kumar Yadav Apr 30 '20 at 05:44
  • Garry is it possible to reset the delay delta from the recoverer added to the interceptor. ``` public class GetCustomerRecoverer implements MethodInvocationRecoverer { @Autowired private LinearBackoffPolicy linearBackoffPolicy; @Override public Customer recover(Object[] args, Throwable cause) { linearBackoffPolicy.setBackOffPeriod(2000L); LOGGER.error("API Retrials exhausted"); throw new RestClientException(cause.getMessage()); } ``` **Need** It is required to reset the delays post each request so that it start again from 1sec onwards. Thanks helping – Shiv Kumar Yadav May 11 '20 at 10:19
  • Please don't put code in comments; it's too hard to read. Edit the question instead and comment that you have done so. `BackOff.start()` is called for each new request so it will automatically reset. – Gary Russell May 11 '20 at 15:00
  • Thanks for the insight Gary. I had extended StatelessBackOffPolicy and thus wasn't asked to override that method. I removed that and it works fine. – Shiv Kumar Yadav May 12 '20 at 06:35