Skip to content

Instantly share code, notes, and snippets.

@zkendall
Created September 7, 2016 00:46
Show Gist options
  • Save zkendall/a7a0f796687b8360d045563c2f75be1c to your computer and use it in GitHub Desktop.
Save zkendall/a7a0f796687b8360d045563c2f75be1c to your computer and use it in GitHub Desktop.
Factory for creating a Spring RetryTemplate, primarily for use for HTTP calls such as with Spring's RestTemplate.
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.HttpHostConnectException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.RetryListener;
import org.springframework.retry.RetryPolicy;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.web.client.HttpServerErrorException;
import java.util.HashMap;
import java.util.Map;
public class RetryTemplateFactory {
private static final Logger DEFAULT_LOGGER = LoggerFactory.getLogger(RetryTemplate.class);
static final Class<? extends Throwable>[] SERVER_RETRYABLES = new Class[]{
HttpServerErrorException.class,
HttpHostConnectException.class,
ConnectTimeoutException.class
};
/**
* Retries HttpServerErrorExceptions, HttpHostConnectException, ConnectTimeoutException.
*/
public static RetryTemplate serverErrorRetry(int initialInterval, int multiplier,
int maxInterval, int maxAttempts, Logger logger) {
return build(initialInterval, multiplier, maxInterval, maxAttempts, logger, SERVER_RETRYABLES);
}
/**
* Build Retry template for specified throwables.
*/
public static RetryTemplate build(int initialInterval, int multiplier,
int maxInterval, int maxAttempts, Logger logger,
Class<? extends Throwable>... throwables) {
SimpleRetryPolicy policy = new SimpleRetryPolicy(maxAttempts, throwableTrueMap(throwables), true);
final RetryTemplate template = buildRetry(policy, initialInterval, multiplier, maxInterval);
if (logger == null) {
logger = DEFAULT_LOGGER;
}
registerLoggingListener(template, logger);
return template;
}
static RetryTemplate buildRetry(RetryPolicy retryPolicy, int initialInterval, int multiplier, int maxInterval) {
ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
backOffPolicy.setInitialInterval(initialInterval);
backOffPolicy.setMultiplier(multiplier);
backOffPolicy.setMaxInterval(maxInterval);
RetryTemplate template = new RetryTemplate();
template.setRetryPolicy(retryPolicy);
template.setBackOffPolicy(backOffPolicy);
return template;
}
/**
* On Error log exception. OnClose Log success/fail so that logs tell complete story.
*/
static void registerLoggingListener(RetryTemplate retryTemplate, Logger log) {
final RetryListener retryListener = new RetryListener() {
@Override
public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
// true == do handle; false == abort
return true;
}
@Override
public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback,
Throwable lastException) {
if (lastException == null) {
if (context.getRetryCount() > 10) {
log.info("Retry finally succeeded! You go glen coco!");
} else if (context.getRetryCount() > 0) {
log.info("Retry succeeded! Hooray.");
}
// else success on first try; don't log.
} else {
log.error("Finished retrying without success.");
}
}
@Override
public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback,
Throwable throwable) {
log.error("Error on attempt #{}.", context.getRetryCount(), throwable);
}
};
retryTemplate.registerListener(retryListener);
}
private static Map throwableTrueMap(Class<? extends Throwable>... items) {
Map<Class<? extends Throwable>, Boolean> map = new HashMap<>();
for (Class<? extends Throwable> throwable : items) {
map.put(throwable, true);
}
return map;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment