范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

通过使用guavaretrying实现灵活的重试机制

  概述
  本文将介绍 guava-retrying 是什么,有什么用,以及如何在项目中合理运用。 guava-retrying 是一个线程安全的 Java 重试类库,提供了一种通用方法去处理任意需要重试的代码。 可以方便灵活地控制重试次数、重试时机、重试频率、停止时机等,并具有异常处理功能。
  主要包括以下内容: guava-retrying 的关键点 guava-retrying 的 maven 依赖 使用场景分析 基本使用 guava-retrying 原理解析 具体的使用场景案例 在 spring boot 中的使用 guava-retrying 的关键点将业务逻辑封装到实现了 Callable 接口的 call 方法中 支持设置当遇到什么异常的时候进行重试操作(也就是重新执行 Callable 接口的 call 方法) 支持设置当 call 方法的返回结果不符合预期的时候进行重试操作 支持设置重试的次数 支持设置每次重试后的等待时间 通过构造器模式创建重试对象 Retryer guava-retrying 的 maven 依赖     com.github.rholder     guava-retrying     2.0.0  使用场景分析由于网络问题需要重试 某个任务的执行时间比较长,可以通过重试来不断检查执行结果是否完成 基本使用定义业务逻辑业务逻辑封装在 Callable 对象中。 Callable callable = () -> {     return thirdApi.invoke(); // 业务逻辑 }; 定义重试器通过构造器模式创建一个 Retryer 重试器对象 // 定义重试器 Retryer retryer = RetryerBuilder.newBuilder()     .retryIfResult(Predicates.isNull()) // 如果结果为空则重试     .retryIfExceptionOfType(IOException.class) // 发生IO异常则重试     .retryIfRuntimeException() // 发生运行时异常则重试     .withWaitStrategy(WaitStrategies.incrementingWait(10, TimeUnit.SECONDS, 10, TimeUnit.SECONDS)) // 每次重试后的等待时间配置:首次10s, 之后每次增加 10s     .withStopStrategy(StopStrategies.stopAfterAttempt(4)) // 停止重试配置:允许执行4次(首次执行 + 最多重试3次)     .build(); 通过重试器来执行代码通过重试器的 call 方法执行业务逻辑代码 try {     retryer.call(callable); // 执行 } catch (final Exception e) { // 重试次数超过阈值或被强制中断     log.error("出现异常", e); } 也可以通过 wrap 方法返回 RetryerCallable 对象,之后再通过 RetryerCallable 对象中的 call 执行业务逻辑 try {     final Retryer.RetryerCallable> retryerCallable = retryer.wrap(callable);     final Map httpResult = retryerCallable.call(); } catch (final Exception e) { // 重试次数超过阈值或被强制中断     log.error("出现异常", e); }
  分析上述代码: 首先定义了一个 Callable 对象,其中执行我们需要重试的业务逻辑。 通过 RetryerBuilder 构造重试器,构造包含如下部分: 重试条件 retryIfResult、retryIfExceptionOfType、retryIfRuntimeException 重试等待策略(延迟)withWaitStrategy 重试停止策略 withStopStrategy 阻塞策略、超时限制、注册重试监听器(上述代码未使用) 通过 retryer.call 执行任务 当重试次数超过设定值或者被强制中断时,会抛出异常,需要捕获处理 guava-retrying 原理解析
  下面是 guava-retrying 的 call 方法的解析 public V call(Callable callable) throws ExecutionException, RetryException {     long startTime = System.nanoTime();     for (int attemptNumber = 1; ; attemptNumber++) { // 1. 通过 for 循环来控制最大的重试次数         Attempt attempt;         try {             V result = attemptTimeLimiter.call(callable); // 2. 执行业务逻辑             attempt = new ResultAttempt(result, attemptNumber, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime));         } catch (Throwable t) { // 3. 执行过程中出现异常后重试             attempt = new ExceptionAttempt(t, attemptNumber, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime));         }          for (RetryListener listener : listeners) { // 4. 增加重试监听             listener.onRetry(attempt);         }          if (!rejectionPredicate.apply(attempt)) { // 5. 判断业务逻辑是否正常执行完毕,是否有异常发生             return attempt.get();         }         if (stopStrategy.shouldStop(attempt)) { // 6. 判断是否终止重试操作             throw new RetryException(attemptNumber, attempt);         } else {             long sleepTime = waitStrategy.computeSleepTime(attempt); // 7. 计算等待时间             try {                 blockStrategy.block(sleepTime); // 8. 阻塞当前线程,执行等待             } catch (InterruptedException e) {                 Thread.currentThread().interrupt();                 throw new RetryException(attemptNumber, attempt);             }         }     } } 具体的使用场景案例
  在下面的案例中通过 MyRetryListener 来监听重试的过程,定义如下  public static class MyRetryListener implements RetryListener {      @Override     public  void onRetry(final Attempt attempt) {         log.info(String.format("执行结果:%s, 异常:%s, 当前重试次数:%s, 当前累计执行时长:%s 毫秒",                 attempt.hasResult() ? attempt.getResult() : null,                 attempt.hasException() ? attempt.getExceptionCause().getClass().getName() : null,                 attempt.getAttemptNumber(),                 attempt.getDelaySinceFirstAttempt()));     } } 执行的结果为空的情况下重试测试代码如下 @Test public void test_retry_getResult() {     // 定义执行任务     final Callable> callable = () -> {         try {             // 暂停 3 s, 模拟数据库查询或者其他耗时的任务             TimeUnit.SECONDS.sleep(3);             // 设置响应结果为 null 的情况             return null;         } catch (final Exception e) {             throw new MyException("执行任务出现异常", e);         }      };      // 定义重试器     final Retryer> retryer = RetryerBuilder.>newBuilder()             .retryIfResult(Predicates.isNull()) // 如果结果为空则重试             .retryIfExceptionOfType(MyException.class) // 发生指定类型的异常则重试             .withRetryListener(new MyRetryListener()) // 出现异常的情况下回调处理             .withWaitStrategy(WaitStrategies                     .incrementingWait(10, TimeUnit.SECONDS, 10, TimeUnit.SECONDS)) // 每次重试后的等待时间配置:首次10s, 之后每次增加 10s             .withStopStrategy(StopStrategies.stopAfterAttempt(4)) // 停止重试配置:允许执行4次(首次执行 + 最多重试3次)             .build();      // 用重试器执行任务     try {         final Map result = retryer.call(callable);         System.out.println(String.format("结果:%s", JsonUtils.toJSONString(result, true)));         Assert.assertTrue(Objects.nonNull(result));     } catch (final Exception e) { // 重试次数超过阈值或被强制中断         log.error("出现异常", e);     } } 通过监听发现重试的原因是:结果为空,具体如下 13:09:30.736 [main] INFO com.ckjava.retrying.TestRetrying - 执行结果:null, 异常:null, 当前重试次数:1, 当前累计执行时长:3003 毫秒 13:09:43.755 [main] INFO com.ckjava.retrying.TestRetrying - 执行结果:null, 异常:null, 当前重试次数:2, 当前累计执行时长:16026 毫秒 13:10:06.766 [main] INFO com.ckjava.retrying.TestRetrying - 执行结果:null, 异常:null, 当前重试次数:3, 当前累计执行时长:39037 毫秒 13:10:39.796 [main] INFO com.ckjava.retrying.TestRetrying - 执行结果:null, 异常:null, 当前重试次数:4, 当前累计执行时长:72067 毫秒 13:10:39.801 [main] ERROR com.ckjava.retrying.TestRetrying - 出现异常 com.github.rholder.retry.RetryException: Retrying failed to complete successfully after 4 attempts. 出现异常的情况下重试测试代码如下 @Test public void test_retry_encounterException() {     // 定义执行任务     final Callable> callable = () -> {         // 暂停 3 s, 模拟请求其他应用的 api 或者容易出现异常的操作         TimeUnit.SECONDS.sleep(3);         // 设置出现异常的情况         throw new MyException("执行任务出现异常");     };      // 定义重试器     final Retryer> retryer = RetryerBuilder.>newBuilder()             .retryIfResult(Predicates.isNull()) // 如果结果为空则重试             .retryIfExceptionOfType(MyException.class) // 发生指定类型的异常则重试             .withRetryListener(new MyRetryListener()) // 出现异常的情况下回调处理             .withWaitStrategy(WaitStrategies                     .incrementingWait(10, TimeUnit.SECONDS, 10, TimeUnit.SECONDS)) // 每次重试后的等待时间配置:首次10s, 之后每次增加 10s             .withStopStrategy(StopStrategies.stopAfterAttempt(4)) // 停止重试配置:允许执行4次(首次执行 + 最多重试3次)             .build();      // 用重试器执行任务     try {         final Map result = retryer.call(callable);         System.out.println(String.format("结果:%s", JsonUtils.toJSONString(result, true)));         Assert.assertTrue(Objects.nonNull(result));     } catch (final Exception e) { // 重试次数超过阈值或被强制中断         log.error("出现异常", e);     } } 通过监听发现重试的原因是:出现了异常,具体如下 13:11:31.581 [main] INFO com.ckjava.retrying.TestRetrying - 执行结果:null, 异常:com.ckjava.retrying.TestRetrying$MyException, 当前重试次数:1, 当前累计执行时长:3009 毫秒 13:11:44.596 [main] INFO com.ckjava.retrying.TestRetrying - 执行结果:null, 异常:com.ckjava.retrying.TestRetrying$MyException, 当前重试次数:2, 当前累计执行时长:16025 毫秒 13:12:07.612 [main] INFO com.ckjava.retrying.TestRetrying - 执行结果:null, 异常:com.ckjava.retrying.TestRetrying$MyException, 当前重试次数:3, 当前累计执行时长:39041 毫秒 13:12:40.625 [main] INFO com.ckjava.retrying.TestRetrying - 执行结果:null, 异常:com.ckjava.retrying.TestRetrying$MyException, 当前重试次数:4, 当前累计执行时长:72054 毫秒 13:12:40.628 [main] ERROR com.ckjava.retrying.TestRetrying - 出现异常 com.github.rholder.retry.RetryException: Retrying failed to complete successfully after 4 attempts. 在 SpringBoot 中的使用
  这里通过调用其他应用的 api 来举例说明具体的使用。 通过@Configuration配置类定义重试器package com.toulezu.test.config;  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.WaitStrategies; import com.google.common.base.Predicates; import com.toulezu.test.exception.MyException; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;  import java.util.Map; import java.util.concurrent.TimeUnit;  @Slf4j @Configuration public class RetryConfig {      @Bean     public Retryer> jiaRiRetry() {         return RetryerBuilder.>newBuilder()                 .retryIfResult(Predicates.isNull()) // 如果结果为空则重试                 .retryIfExceptionOfType(MyException.class) // 发生指定类型的异常则重试                 .withRetryListener(new MyRetryListener()) // 出现异常的情况下回调处理                 .withWaitStrategy(WaitStrategies                         .incrementingWait(10, TimeUnit.SECONDS, 10, TimeUnit.SECONDS)) // 每次重试后的等待时间配置:首次10s, 之后每次增加 10s                 .withStopStrategy(StopStrategies.stopAfterAttempt(4)) // 停止重试配置:允许执行4次(首次执行 + 最多重试3次)                 .build();     }      /**      * 重试监听处理      */     public static class MyRetryListener implements RetryListener {          @Override         public  void onRetry(final Attempt attempt) {             log.info(String.format("执行结果:%s, 异常:%s, 当前重试次数:%s, 当前累计执行时长:%s 毫秒",                     attempt.hasResult() ? attempt.getResult() : null,                     attempt.hasException() ? attempt.getExceptionCause().getClass().getName() : null,                     attempt.getAttemptNumber(),                     attempt.getDelaySinceFirstAttempt()));         }     } }  定义业务逻辑package com.toulezu.test.function;  import com.ckjava.xutils.HttpClientUtils; import com.ckjava.xutils.JsonUtils; import com.ckjava.xutils.http.HttpResult; import com.fasterxml.jackson.core.type.TypeReference; import com.toulezu.test.exception.MyException;  import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.concurrent.Callable;  /**  * @author ckjava  *  */ public class JiaRiCallable implements Callable> {      private String year;      public JiaRiCallable(final String year) {         this.year = year;     }      @Override     public Map call() throws Exception {         final Map headers = new HashMap<>(1);         headers.put("Content-Type", "application/json; charset=utf-8");         final Map params = new HashMap<>(1);         params.put("d", year);         final HttpResult httpResult =                 HttpClientUtils.get(HttpClientUtils.HttpRequestInfo.builder().url("http://tool.bitefu.net/jiari").headers(headers).parameters(params)                         .build());         try {             final Map result = JsonUtils.readJavaObject(httpResult.getResponseBody(), new TypeReference>() {             }).orElse(null);             return result;         } catch (final Exception e) {             throw new MyException("解析响应报文出现异常", e);         }     } }  通过重试器执行业务逻辑package com.toulezu.test.web;  import com.ckjava.xutils.http.HttpResponse; import com.github.rholder.retry.Retryer; import com.toulezu.test.function.JiaRiCallable; import io.swagger.annotations.Api; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController;  import javax.annotation.Resource; import java.util.Map;  @Api @RestController public class JiaRiController {      @Resource     private Retryer> jiaRiRetry;      @GetMapping(value = "/jiaRi")     public HttpResponse> getJiaRi(             @RequestParam String year) {         try {             return HttpResponse.getReturn(jiaRiRetry.call(new JiaRiCallable(year)), 200, null);         } catch (Exception e) {           return HttpResponse.getReturn(e);         }     } }

趋势!浙大撤销10个本科专业的同时,新增了这两大热门专业近日,浙江大学公布了一则重磅消息,宣布新增机器人工程和人工智能两个热门本科专业,撤销包括应用化学生物化学中药学护理学通信工程电子商务等十个本科专业。同时,今年浙江大学将在竺可桢学院华为官宣4月11日MateBookXPro和MateBook14冲刺来见你准备好了吗就在4月3日,华为平板和笔记本官微发布了一段有关一碰传功能的演示视频,并配上快,有多快?4月11日,冲刺来见文字,吊足了国内用户的胃口。没错,全新华为MateBookXPro和Ma6天5个涨停空壳一汽夏利作妖一汽夏利正筹划与国内新能源车企合作,生产新能源汽车,复牌再度涨停的一汽夏利或将摆脱作为壳资源被出售的窘境。4月10日,一汽夏利(000927。SZ)再度一字板涨停。一汽夏利从4月8号称半年后仅眼镜大小,美军特供版HoloLens2来了去年11月,彭博曾报道微软赢得4。8亿美元军事合同,为陆军开发用于作战和训练的原型AR头显。据悉,这个军事合同来自于美军的HUD3。0计划,目前该计划已经更名为集成视觉增强系统(I华为P30代言人曝光?娜扎和景甜喜提华为P30ProPConline资讯4月8日,景甜和娜扎先后使用华为P30Pro发了一条微博,之后华为终端公司官微转发了景甜的微博。疑似景甜和娜扎将作为华为P30Pro的代言人。4月11日,华为将万达百货改名苏宁百货?王健林抛掉的鸡肋,苏宁为什么要接盘4月10日下午消息,苏宁易购收购万达百货进入实质性整合阶段。37位万达百货总经理已抵达南京苏宁总部参加月度例会,这也意味着苏宁易购管理团队已全面接手万达百货运营工作,完成收购交割预关心自己的肾健康?这只智能笔可以让你在家就能体检最近,极客之选体验了一款新的健康检测设备HiPee智能健康精灵S1菁英版(以下简称HiPeeS1),它能够检测6项尿检指标,而且体积小巧便携。从能测量心率的智能手表到便携式的血压仪官宣!4月10日起,天弘余额宝全面取消限购4月9日晚间,天弘基金管理有限公司发布公告称,将于4月10日起取消天弘余额宝货币市场基金个人交易账户持有额度及单日申购额度限制。投资者购买天弘余额宝货币基金将不再受到单日2万元的申银行短信提醒服务被指存陷阱!单方面涨价1元,有用户被自动开通日前,有网友投诉,中国工商银行短信提醒服务悄悄涨价,由每月2元涨至3元,这种单方面擅自涨价的行为,侵犯了自身权益。中国工商银行对此回应称,调价前已发布了调整余额变动提醒短信服务价格四月不建议入手的4款手机,我劝你尽量别入坑!转眼间已经到了四月份,年初手机市场也是迎来了新机发布以及老机型降价的高峰期,一时间许多小伙伴也是有了购买新机的需求,不过话又说回来,由于自身数码知识的不足以及厂商的卖力营销,许多小上海打响汽车以旧换新第一枪!上汽集团派发30亿元红包,汽车消费市场迎来利好!天天财经独家,速关注今天,上海的朋友们迎来汽车消费利好政策。4月10日,据上海市政府官方微信消息,上海市即日起将启动老旧汽车以旧换新活动。针对沪牌注册登记的国三及以下排放标准的老旧
中华酷联大洗牌!华为屡获佳绩,联想成为众矢之的,中兴酷派呢?10年前,中兴华为联想和酷派是国内科技领域的明日之星,肩负着科技圈研发创新的重任,因此又被国人亲切地称之为中华酷联。十年后的今天,它们的现状又如何呢?咱们一起来看看。众矢之的的联想顶级旗舰巅峰对决,谁才是国产高端旗舰的门面?华为手机业务遭受重创后,虽然市场份额不断萎缩沦为other,但好在MateP系列名声在外,以至于在高端市场仍然具有一定的竞争力。不过,随着其他国产品牌在高端旗舰领域的不断发力,华为华为Mate50华为当前的境况相信大家都清楚,因为多到面制约,华为所有手机均无法使用5G芯片,致使华为在很长一段时间内,都没有发布新机,虽然在多方努力之下,华为P50与华为Nova9均已发布,但与你在马路上遇到过电单车的无理行为吗?说起这个电单车的无理行为我的确是要吐槽一下的。每天我踩单车去地铁站,路上总会遇到一些电单车,有些人骑电单车真的有很多不好的行为啊!他们骑着电单车,遇到前面有行人或者骑单车的人在堵住银行APP越长越像?!ampampquot零售之王ampampquotAPP10。0上线,ampampquot开放ampampquot成关键词,来看有哪些独招开放势头愈演愈烈,手机银行APP或主动或被倒逼着掀起了新一轮的进化由最初的交易工具交易渠道演化为开放平台,主动敞开大门引入外部资管机构资管产品到自家面客,这是越来越多银行正在做的事媒介之变元宇宙热潮一场数字社会大跃进文龚伟亮(中国传媒大学传播研究院副教授)元宇宙这场带有显著资本主导权力重塑特征的科技整合和数字社会跃进,背后的公共性是个很大的问题。在这个由资本执牛耳的宇宙设想里不仅有对老年人口农为什么有听力损失后都要尽早选配助听器呢?应早发现,早干预,早语训,可以缓解听力下降,保护言语能力,解决沟通障碍,改善生活质量。您好,有听力下降要尽早选配助听器进行干预,这样可以避免因听不到,大脑接收的语言信息减少时间久了听力高频全部丢失,低频几乎在正常范围,戴助听器还有效果么?低频正常,高频听损严重,配戴助听器是有效果的。建议选择多通道的助听器,在不同的频率段根据听损给予合理的有效的补偿。高频部分的听力差会出现听得见却听不清的情况,因为高频听力决定了言语ampampquot每天一遍,爱上Pythonampampquot机器学习入门原理篇前言随着前端智能化的火热,AI机器学习进入前端开发者们的视野。AI能够解决编程领域不能直接通过规则和运算解决的问题,通过自动推理产出最佳策略,成为了前端工程师们解决问题的又一大利器12。8日白酒,半导体,电力,新能源车,光伏,券商,生物医药白酒,半导体,电力,新能源车,光伏,证券,生物医药明日走势预判!1白酒行业今日放量大涨,一举突破上方压力位,全天收光头大阳线。趋势上没有问题。指标上,只有五分钟级别有顶背离结构。个俄罗斯将开始全面使用3D打印制造飞机零部件近日,俄罗斯国家技术集团宣布,该集团下属的增材技术中心已获得俄联邦工业和贸易部批准,可进行航空部件和其他零配件的批量化3D打印生产。这意味着俄罗斯航空制造业将开始全面使用3D打印制