11

I'm reading up on GCM: https://developers.google.com/cloud-messaging/server

and one of the requirements is that the server needs to be able to:

  • handle requests and resend them using exponential back-off.

I use Spring RestTemplate for my backend which comes from Spring Boot. There doesn't seem to be a method which I can use to set my retry policy in the docs: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html

Also when I googled, I found the RetryTemplate, but it is part of Spring Batch and doesn't extend RestTemplate which makes me think that it is not supposed to be used for Rest operations, but rather Spring Batch operations like processing large amount of transactions: http://docs.spring.io/spring-batch/2.1.x/apidocs/org/springframework/batch/retry/support/RetryTemplate.html

Is there a way I can use exponential backoff with Spring RestTemplate?

Simon
  • 19,658
  • 27
  • 149
  • 217
  • 3
    https://github.com/rholder/guava-retrying has an exponential backoff retry strategy. It's a general flexible retryer, that you can use to retry whatever you want. – JB Nizet Aug 09 '15 at 16:51
  • 1
    You can add spring-retry as a dependency to handle Retry https://github.com/spring-projects/spring-retry. – Nitin Arora Aug 10 '15 at 04:40
  • 1
    We have such implementation in the core framework for the JMS support. This is an interesting idea. Could you please create an issue [in the Spring Framework issue tracker](https://jira.spring.io/browse/SPR)? Thanks! – Stephane Nicoll Aug 10 '15 at 07:50
  • Thanks, I will create an issue once I'm back by my Pc. For now, I think I will just try out guava-retry as a starting point. – Simon Aug 10 '15 at 07:54
  • Issue is created: https://jira.spring.io/browse/SPR-13336 – Simon Aug 10 '15 at 09:53

2 Answers2

7

Good day!

I guess, desired behavior could be achived by implementing custom Sleeper class.

Next you need to set this sleeper to BackOffPolicy as follows:

public class RetryTest {

  public static final Logger LOG = LoggerFactory.getLogger(RetryTemplate.class);

  @org.junit.Test
  public void testRT() {
    RetryTemplate retryTemplate = new RetryTemplate();
    final SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
    retryPolicy.setMaxAttempts(5);
    retryTemplate.setRetryPolicy(retryPolicy);

    Sleeper sleeper = new Sleeper() {
      private long timeToSleep = 0;
      @Override
      public void sleep(long timeout) throws InterruptedException {
        if (timeToSleep ==0) {
          timeToSleep = timeout;
        } else {
          timeToSleep = (long) (timeToSleep * Math.E);
        }
        LOG.warn("sleeping for: {}", timeToSleep);
        Thread.sleep(timeToSleep);
      }
    };
    FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy().withSleeper(sleeper);
    retryTemplate.setBackOffPolicy(backOffPolicy);
    retryTemplate.execute(new RetryCallback<Void, ResourceAccessException>() {
      @Override
      public Void doWithRetry(RetryContext retryContext) throws ResourceAccessException {
        LOG.debug(">RetryCount: {}", retryContext.getRetryCount());
        new RestTemplate().getForObject("https://unreachable.host", String.class);
        return null;
      }
    });
  }
}

Also there is ExponentialBackOffPolicy by spring-retry.

Hope this would help.

Konstantin Konyshev
  • 1,026
  • 9
  • 18
6

You can use like the below code .

@Retryable(exceptionExpression="#{@exceptionChecker.shouldRetry(#root)}",
  maxAttemptsExpression = "#{@integerFiveBean}",
  backoff = @Backoff(delayExpression = "#{1}", 
    maxDelayExpression = "#{5}", multiplierExpression = "#{1.1}"))
public void service3() {
  ...
}
ochs.tobi
  • 3,214
  • 7
  • 31
  • 52
Vikesh Royal
  • 81
  • 1
  • 3