Merge pull request #1 from garyrussell/AMQP-226

* AMQP-226:
  AMQP-226 Fix Exponential Back Off
This commit is contained in:
Oleg Zhurakousky
2012-05-10 10:12:27 -04:00
3 changed files with 67 additions and 6 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2007 the original author or authors.
* Copyright 2006-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,8 @@
package org.springframework.retry.backoff;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.retry.RetryContext;
import org.springframework.util.ClassUtils;
@@ -35,9 +37,11 @@ import org.springframework.util.ClassUtils;
*
* @author Rob Harrop
* @author Dave Syer
* @author Gary Russell
*/
public class ExponentialBackOffPolicy implements BackOffPolicy {
protected final Log logger = LogFactory.getLog(this.getClass());
/**
* The default 'initialInterval' value - 100 millisecs. Coupled with the
* default 'multiplier' value this gives a useful initial spread of pauses
@@ -151,7 +155,11 @@ public class ExponentialBackOffPolicy implements BackOffPolicy {
public void backOff(BackOffContext backOffContext) throws BackOffInterruptedException {
ExponentialBackOffContext context = (ExponentialBackOffContext) backOffContext;
try {
sleeper.sleep(context.getSleepAndIncrement());
long sleepTime = context.getSleepAndIncrement();
if (logger.isDebugEnabled()) {
logger.debug("Sleeping for " + sleepTime);
}
sleeper.sleep(sleepTime);
}
catch (InterruptedException e) {
throw new BackOffInterruptedException("Thread interrupted while sleeping", e);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2007 the original author or authors.
* Copyright 2006-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@ import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.AttributeAccessor;
import org.springframework.retry.ExhaustedRetryException;
import org.springframework.retry.RecoveryCallback;
import org.springframework.retry.RetryCallback;
@@ -67,6 +68,7 @@ import org.springframework.retry.policy.SimpleRetryPolicy;
*
* @author Rob Harrop
* @author Dave Syer
* @author Gary Russell
*/
public class RetryTemplate implements RetryOperations {
@@ -220,8 +222,22 @@ public class RetryTemplate implements RetryOperations {
throw new TerminatedRetryException("Retry terminated abnormally by interceptor before first attempt");
}
// Start the backoff context...
BackOffContext backOffContext = backOffPolicy.start(context);
// Get or Start the backoff context...
BackOffContext backOffContext = null;
AttributeAccessor attributeAccessor = null;
if (context instanceof AttributeAccessor) {
attributeAccessor = (AttributeAccessor) context;
Object resource = attributeAccessor.getAttribute("backOffContext");
if (resource instanceof BackOffContext) {
backOffContext = (BackOffContext) resource;
}
}
if (backOffContext == null) {
backOffContext = backOffPolicy.start(context);
if (attributeAccessor != null && backOffContext != null) {
attributeAccessor.setAttribute("backOffContext", backOffContext);
}
}
/*
* We allow the whole loop to be skipped if the policy or context

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2007 the original author or authors.
* Copyright 2006-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,18 +22,23 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
import org.springframework.retry.ExhaustedRetryException;
import org.springframework.retry.RecoveryCallback;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.RetryState;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.support.DefaultRetryState;
import org.springframework.retry.support.RetryTemplate;
/**
* @author Dave Syer
* @author Gary Russell
*
*/
public class StatefulRetryIntegrationTests {
@@ -114,6 +119,38 @@ public class StatefulRetryIntegrationTests {
assertEquals("bar", result);
}
@Test
public void testExponentialBackOffIsExponential() throws Exception {
ExponentialBackOffPolicy policy = new ExponentialBackOffPolicy();
policy.setInitialInterval(100);
policy.setMultiplier(1.5);
RetryTemplate template = new RetryTemplate();
template.setBackOffPolicy(policy);
final List<Long> times = new ArrayList<Long>();
RetryState retryState = new DefaultRetryState("bar");
for (int i = 0; i < 3; i++) {
try {
template.execute(new RetryCallback<String>() {
public String doWithRetry(RetryContext context) throws Exception {
times.add(System.currentTimeMillis());
throw new Exception("Fail");
}
}, new RecoveryCallback<String>() {
public String recover(RetryContext context)
throws Exception {
return null;
}
}, retryState);
}
catch (Exception e) {
assertTrue(e.getMessage().equals("Fail"));
}
}
assertEquals(3, times.size());
assertTrue(times.get(1) - times.get(0) >= 100);
assertTrue(times.get(2) - times.get(1) >= 150);
}
/**
* @author Dave Syer
*