在平常开发中,咱们常常会遇到须要调用外部服务和接口的场景。外部服务对于调用者来讲通常都是不可靠的,尤为是在网络环境比较差的状况下,网络抖动很容易致使请求超时等异常状况,这时候就须要使用失败重试策略从新调用 API 接口来获取。重试策略在服务治理方面也有很普遍的使用,经过定时检测,来查看服务是否存活(
Active)。java
Guava Retrying 是一个灵活方便的重试组件,包含了多种的重试策略,并且扩展起来很是容易。git
用做者的话来讲:github
This is a small extension to Google’s Guava library to allow for the creation of configurable retrying strategies for an arbitrary function call, such as something that talks to a remote service with flaky uptime.网络
使用 Guava-retrying 你能够自定义来执行重试,同时也能够监控每次重试的结果和行为,最重要的基于 Guava 风格的重试方式真的很方便。app
如下会简单列出 guava-retrying 的使用方式:dom
Callable<Integer> task = new Callable<Integer>() { @Override public Integer call() throws Exception { return 2; } }; Retryer<Integer> retryer = RetryerBuilder.<Integer>newBuilder() .retryIfResult(Predicates.<Integer>isNull()) .retryIfResult(Predicates.equalTo(2)) .retryIfExceptionOfType(IOException.class) .withStopStrategy(StopStrategies.stopAfterAttempt(3)) .withWaitStrategy(WaitStrategies.fixedWait(300, TimeUnit.MILLISECONDS)) .build(); try { retryer.call(task); } catch (ExecutionException e) { e.printStackTrace(); } catch (RetryException e) { e.printStackTrace(); }
@Override public Integer call() throws Exception { return 2; } }; Retryer<Integer> retryer = RetryerBuilder.<Integer>newBuilder() .retryIfException() .withStopStrategy(StopStrategies.stopAfterDelay(30,TimeUnit.SECONDS)) .withWaitStrategy(WaitStrategies.incrementingWait(3, TimeUnit.SECONDS,1,TimeUnit.SECONDS)) .withAttemptTimeLimiter(AttemptTimeLimiters.<Integer>fixedTimeLimit(3,TimeUnit.SECONDS)) .withRetryListener(new RetryListener() { @Override public <V> void onRetry(Attempt<V> attempt) { if (attempt.hasException()){ attempt.getExceptionCause().printStackTrace(); } } }) .build(); try { retryer.call(task); } catch (ExecutionException e) { e.printStackTrace(); } catch (RetryException e) { e.printStackTrace(); }
long startTime = System.nanoTime(); for (int attemptNumber = 1; ; attemptNumber++) { Attempt<V> attempt; try { // 执行成功 V result = attemptTimeLimiter.call(callable); attempt = new ResultAttempt<V>(result, attemptNumber, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)); } catch (Throwable t) { // 执行失败 attempt = new ExceptionAttempt<V>(t, attemptNumber, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)); } // 监听器处理 for (RetryListener listener : listeners) { listener.onRetry(attempt); } // 是否符合终止策略 if (!rejectionPredicate.apply(attempt)) { return attempt.get(); } // 是否符合中止策略 if (stopStrategy.shouldStop(attempt)) { throw new RetryException(attemptNumber, attempt); } else { // 计算下次重试间隔时间 long sleepTime = waitStrategy.computeSleepTime(attempt); try { blockStrategy.block(sleepTime); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RetryException(attemptNumber, attempt); } } }
<dependency> <groupId>com.github.rholder</groupId> <artifactId>guava-retrying</artifactId> <version>2.0.0</version> </dependency>
默认的guava中也有包含。异步
Attempt:一次执行任务;ide
AttemptTimeLimiter:单次任务执行时间限制(若是单次任务执行超时,则终止执行当前任务);ui
BlockStrategies:任务阻塞策略(通俗的讲就是当前任务执行完,下次任务还没开始这段时间作什么……),默认策略为:BlockStrategies.THREAD_SLEEP_STRATEGY 也就是调用 Thread.sleep(sleepTime);日志
RetryException:重试异常;
RetryListener:自定义重试监听器,能够用于异步记录错误日志;
StopStrategy:中止重试策略,提供三种:
WaitStrategy:等待时长策略(控制时间间隔),返回结果为下次执行时长: