博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
重试利器之Guava-Retryer
阅读量:7010 次
发布时间:2019-06-28

本文共 4785 字,大约阅读时间需要 15 分钟。

写在前面

在日常开发中,我们经常会遇到需要调用外部服务和接口的场景。外部服务对于调用者来说一般都是不可靠的,尤其是在网络环境比较差的情况下,网络抖动很容易导致请求超时等异常情况,这时候就需要使用失败重试策略重新调用 API 接口来获取。重试策略在服务治理方面也有很广泛的使用,通过定时检测,来查看服务是否存活(Active)。

Guava Retrying是一个灵活方便的重试组件,包含了多种的重试策略,而且扩展起来非常容易。

用作者的话来说:

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 风格的重试方式真的很方便。

代码示例

  • 引入Guava-retry
2.0.0
com.github.rholder
guava-retrying
${guava-retry.version}
复制代码
  • 定义实现Callable接口的方法,以便Guava retryer能够调用
/**    * @desc 更新可代理报销人接口    * @author jianzhang11    * @date 2017/3/31 15:17    */   private static Callable
updateReimAgentsCall = new Callable
() { @Override public Boolean call() throws Exception { String url = ConfigureUtil.get(OaConstants.OA_REIM_AGENT); String result = HttpMethod.post(url, new ArrayList
()); if(StringUtils.isEmpty(result)){ throw new RemoteException("获取OA可报销代理人接口异常"); } List
oaReimAgents = JSON.parseArray(result, OAReimAgents.class); if(CollectionUtils.isNotEmpty(oaReimAgents)){ CacheUtil.put(Constants.REIM_AGENT_KEY,oaReimAgents); return true; } return false; } };复制代码
  • 定义Retry对象并设置相关策略
Retryer
retryer = RetryerBuilder .
newBuilder() //抛出runtime异常、checked异常时都会重试,但是抛出error不会重试。 .retryIfException() //返回false也需要重试 .retryIfResult(Predicates.equalTo(false)) //重调策略 .withWaitStrategy(WaitStrategies.fixedWait(10, TimeUnit.SECONDS)) //尝试次数 .withStopStrategy(StopStrategies.stopAfterAttempt(3)) .build(); try { retryer.call(updateReimAgentsCall); } catch (ExecutionException e) {// e.printStackTrace(); } catch (RetryException e) { logger.error("更新可代理报销人异常,需要发送提醒邮件"); }复制代码

简单三步就能使用Guava Retryer优雅的实现重调方法。

接下来对其进行详细说明:

  • RetryerBuilder是一个factory创建者,可以定制设置重试源且可以支持多个重试源,可以配置重试次数或重试超时时间,以及可以配置等待时间间隔,创建重试者Retryer实例。
  • RetryerBuilder的重试源支持Exception异常对象 和自定义断言对象,通过retryIfExceptionretryIfResult设置,同时支持多个且能兼容。
  • retryIfException,抛出runtime异常、checked异常时都会重试,但是抛出error不会重试。
  • retryIfRuntimeException只会在抛runtime异常的时候才重试,checked异常和error都不重试。
  • retryIfExceptionOfType允许我们只在发生特定异常的时候才重试,比如NullPointerException和IllegalStateException`都属于runtime异常,也包括自定义的error

如:

.retryIfExceptionOfType(Error.class)// 只在抛出error重试复制代码

当然我们还可以在只有出现指定的异常的时候才重试,如:

.retryIfExceptionOfType(IllegalStateException.class)  .retryIfExceptionOfType(NullPointerException.class)复制代码

或者通过Predicate实现

.retryIfException(Predicates.or(Predicates.instanceOf(NullPointerException.class),                  Predicates.instanceOf(IllegalStateException.class)))复制代码

retryIfResult可以指定你的Callable方法在返回值的时候进行重试,如

// 返回false重试 .retryIfResult(Predicates.equalTo(false))  //以_error结尾才重试 .retryIfResult(Predicates.containsPattern("_error$"))  复制代码

当发生重试之后,假如我们需要做一些额外的处理动作,比如发个告警邮件啥的,那么可以使用RetryListener。每次重试之后,guava-retrying会自动回调我们注册的监听。可以注册多个RetryListener,会按照注册顺序依次调用。

import com.github.rholder.retry.Attempt;  import com.github.rholder.retry.RetryListener;    import java.util.concurrent.ExecutionException;    public class MyRetryListener
implements RetryListener { @Override public
void onRetry(Attempt
attempt) { // 第几次重试,(注意:第一次重试其实是第一次调用) System.out.print("[retry]time=" + attempt.getAttemptNumber()); // 距离第一次重试的延迟 System.out.print(",delay=" + attempt.getDelaySinceFirstAttempt()); // 重试结果: 是异常终止, 还是正常返回 System.out.print(",hasException=" + attempt.hasException()); System.out.print(",hasResult=" + attempt.hasResult()); // 是什么原因导致异常 if (attempt.hasException()) { System.out.print(",causeBy=" + attempt.getExceptionCause().toString()); } else { // 正常返回时的结果 System.out.print(",result=" + attempt.getResult()); } // bad practice: 增加了额外的异常处理代码 try { Boolean result = attempt.get(); System.out.print(",rude get=" + result); } catch (ExecutionException e) { System.err.println("this attempt produce exception." + e.getCause().toString()); } System.out.println(); } } 复制代码

接下来在Retry对象中指定监听:

.withRetryListener(new MyRetryListener<>())复制代码

参考资料:

转载地址:http://hwxtl.baihongyu.com/

你可能感兴趣的文章
100%布局的头部,内部内容960居中出现滚动条的时候,注意的小东西
查看>>
Ubuntu系统里下载安装配置redis-2.2.13.tar.gz
查看>>
2017年PHP程序员未来路在何方
查看>>
vue - webpack.base.conf.js
查看>>
MongoDB 主从复制小实验
查看>>
Linux Shell常用技巧(七)
查看>>
iOS网络编程解析协议二:XML数据传输解析
查看>>
Leetcode: Concatenated Words
查看>>
Python 多线程
查看>>
oracle数据库性能
查看>>
关于VS中的调试信息输出
查看>>
IOS-5个可以帮你优化App的优秀网站
查看>>
ArrayIndexOutOfBoundsException
查看>>
JAVA判断各种类型数据是否为空
查看>>
如何使用kali的Searchsploit查找软件漏洞
查看>>
Vim for Rails developers: Lazy modern configuration
查看>>
小鹏G3完成两轮三高测试 夏珩:该走的路我们一步不少走
查看>>
西班牙多地拉响“黄色大风”警报 华人出行需谨慎
查看>>
程序员必知的七个图形工具
查看>>
iOS 无需官方SDK实现微信、QQ社交功能,支持Web登录
查看>>