使用背景
需要重复尝试执行某些动作,guava-retrying 提供了成型的重试框架
依赖
<dependency><groupId>com.github.rholder</groupId><artifactId>guava-retrying</artifactId><version>${retrying.version}</version><exclusions><exclusion><groupId>com.google.guava</groupId><artifactId>guava</artifactId></exclusion></exclusions></dependency>
${retrying.version} 实际为 2.0.0
如果已有 guava 缓存框架引入则可以像上面一样去除,否则可以保留
定义工具类
import com.github.rholder.retry.Attempt;
import com.github.rholder.retry.RetryListener;
import com.github.rholder.retry.Retryer;
import com.github.rholder.retry.RetryerBuilder;
import com.github.rholder.retry.StopStrategies;
import com.github.rholder.retry.StopStrategy;
import com.github.rholder.retry.WaitStrategies;
import com.google.common.base.Predicate;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.time.StopWatch;import java.text.MessageFormat;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;@Slf4j
public class RetryUtil {private RetryUtil(){}/*** 根据输入的condition重复做task,在规定的次数内达到condition则返回,* 如果超过retryTimes则返回null, 重试次数,整个重试时间以及retry exception都会记录log* 需要注意调用的时候需要新起一个线程,不然重试失败会阻塞当前线程** @param condition 重试条件,比如接口返回errorCode为处理中,或不是最终需要的结果* @param task 重试做的任务* @param sleepTime 重试间隔时间,单位毫秒* @param retryTimes 最大重试次数* @return targetBean*/public static <V> Optional<V> retry(Predicate<V> condition, Callable<V> task, int sleepTime, Integer retryTimes) {Optional<V> result = Optional.empty();StopStrategy stopStrategy = null;if (retryTimes == null) {stopStrategy = StopStrategies.neverStop();} else {stopStrategy = StopStrategies.stopAfterAttempt(retryTimes);}StopWatch stopWatch = new StopWatch();try {stopWatch.start();Retryer<V> retry = RetryerBuilder.<V>newBuilder()// 默认任务执行过程中发生异常自动重试.retryIfException()// 重试条件(按照业务场景).retryIfResult(condition)// 等待策略.withWaitStrategy(WaitStrategies.fixedWait(sleepTime, TimeUnit.MILLISECONDS))// 重试策略.withStopStrategy(stopStrategy)// 重试监听器.withRetryListener(new RetryListener() {@Overridepublic <V> void onRetry(Attempt<V> attempt) {// 记录重试次数和异常信息log.info(MessageFormat.format("{0}th retry", attempt.getAttemptNumber()));if (attempt.hasException()) {log.error(MessageFormat.format("retry exception:{0}", attempt.getExceptionCause()));}}}).build();// 开始执行重试任务result = Optional.ofNullable(retry.call(task));} catch (Exception e) {log.error("retry fail:", e);} finally {stopWatch.stop();log.info("retry execute time" + stopWatch.getTime());}return result;}
}
实际使用
private void xxxxXxxxx() {Predicate<Boolean> condition = result -> result;RetryUtil.retry(condition::test,() -> xxxxxxService.xxxxXxxx(),60000,60);}
其中 xxxxxxService.xxxxXxxx() : 方法为要重试的内容,同时改方法要返回
条件的指定类型。
第一个为入参为重试条件。
60000 代表重试时间间隔,单位 毫秒
60 标识重试次数