Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

AMQP-226 Fix Exponential Back Off

Previously, for stateful environments,the
multiplier had no effect and the backoff
policy always slept for the initial interval.

AMQP-226 Polishing

Using AttributeAccessor interface instead of concrete
RetryContextSupport.
  • Loading branch information...
commit c53f1f09d1d16d72575af6b646569e82796bdfcb 1 parent c36d1f6
@garyrussell garyrussell authored Oleg Zhurakousky committed
View
12 src/main/java/org/springframework/retry/backoff/ExponentialBackOffPolicy.java
@@ -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 @@
*
* @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 BackOffContext start(RetryContext context) {
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
22 src/main/java/org/springframework/retry/support/RetryTemplate.java
@@ -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 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 @@
*
* @author Rob Harrop
* @author Dave Syer
+ * @author Gary Russell
*/
public class RetryTemplate implements RetryOperations {
@@ -220,8 +222,22 @@ public void setRetryPolicy(RetryPolicy retryPolicy) {
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
39 src/test/java/org/springframework/retry/policy/StatefulRetryIntegrationTests.java
@@ -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.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 void testExternalRetryWithSuccessOnRetry() throws Exception {
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
*
Please sign in to comment.
Something went wrong with that request. Please try again.