Guava Retryer实现接口重试的示例

目录
  • 前言
  • Guava Retryer
    • 引入依赖
    • 快速开始
    • 指数退避(Exponential Backoff)
    • 斐波那契退避(Fibonacci Backoff)
    • 重试监听器
  • 小结

前言

小黑在开发中遇到个问题,我负责的模块需要调用某个三方服务接口查询信息,查询结果直接影响后续业务逻辑的处理;

这个接口偶尔会因网络问题出现超时,导致我的业务逻辑无法继续处理;

这个问题该如何解决呢?,小黑首先想到的就是重试嘛,如果失败了就再调用一次。

问题来了,如果又失败了呢?接着重试嘛。我们循环处理,比如循环5次,全失败则任务服务不可用,结束调用。

如果我又想着5次调用间隔一段时间呢?第一次先隔1秒,然后3秒,然后5秒呢?

小黑发现事情没那么简单,如果自己搞容易出BUG呀。

转念一想,这个常见挺常见,网上应该有轮子呀,找找看。一不小心就让我给找着啦,哈哈。

Guava Retryer

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 Retryer你可以自定义来执行重试,同时也可以监控每次重试的结果和行为,最重要的基于 Guava 风格的重试方式真的很方便。

引入依赖

<dependency>
      <groupId>com.github.rholder</groupId>
      <artifactId>guava-retrying</artifactId>
      <version>2.0.0</version>
</dependency>

快速开始

Callable<Boolean> callable = new Callable<Boolean>() {
    public Boolean call() throws Exception {
        return true; // do something useful here
    }
};

Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
    .retryIfResult(Predicates.<Boolean>isNull()) // callable返回null时重试
    .retryIfExceptionOfType(IOException.class) // callable抛出IOException重试
    .retryIfRuntimeException() // callable抛出RuntimeException重试
    .withStopStrategy(StopStrategies.stopAfterAttempt(3)) // 重试3次后停止
    .build();
try {
    retryer.call(callable);
} catch (RetryException e) {
    e.printStackTrace();
} catch (ExecutionException e) {
    e.printStackTrace();
}

在Callable的call()方法返回null,抛出IOException或者RuntimeException时会重试;
将在尝试重试3次后停止,并抛出包含上次失败尝试信息的RetryException;
如果call()方法中弹出任何其他异常,它将被包装并在ExecutionException中重新调用。

指数退避(Exponential Backoff)

根据wiki上对Exponential backoff的说明,指数补偿是一种通过反馈,成倍地降低某个过程的速率,以逐渐找到合适速率的算法。

在以太网中,该算法通常用于冲突后的调度重传。根据时隙和重传尝试次数来决定延迟重传。

在c次碰撞后(比如请求失败),会选择0和2^c - 1之间的随机值作为时隙的数量。

对于第1次碰撞来说,每个发送者将会等待0或1个时隙进行发送。
而在第2次碰撞后,发送者将会等待0到3( 由2^2 -1 计算得到)个时隙进行发送。
而在第3次碰撞后,发送者将会等待0到7( 由2^3 - 1 计算得到)个时隙进行发送。
以此类推……

Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
        .retryIfExceptionOfType(IOException.class)
        .retryIfRuntimeException()
        .withWaitStrategy(WaitStrategies.exponentialWait(100, 5, TimeUnit.MINUTES)) // 指数退避
        .withStopStrategy(StopStrategies.neverStop()) // 永远不停止重试
        .build();

创建一个永远重试的重试器,在每次重试失败后以指数级退避间隔递增,直到最多5分钟。5分钟后,从那时起每隔5分钟重试一次。

斐波那契退避(Fibonacci Backoff)

斐波那契数列指的是这样一个数列:

0,1,1,2,3,5,8,13,21,34,55,89...

这个数列从第3项开始,每一项都等于前两项之和。

Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
        .retryIfExceptionOfType(IOException.class)
        .retryIfRuntimeException()
        .withWaitStrategy(WaitStrategies.fibonacciWait(100, 2, TimeUnit.MINUTES)) // 斐波那契退避
        .withStopStrategy(StopStrategies.neverStop())
        .build();

创建一个永远重试的重试器,在每次重试失败后以增加斐波那契退避间隔的方式等待,直到最多2分钟。2分钟后,从那时起每隔2分钟重试一次。

与指数退避策略类似,斐波那契退避策略遵循一种模式,即在每次尝试失败后等待的时间越来越长。

对于这两种策略的性能英国利兹大学专门做过性能测试,相比指数退避策略,斐波那契退避策略可能性能更好,吞吐量可能也更好。

重试监听器

当重试发生时,如果需要额外做一些动作,比如发送邮件通知之类的,可以通过RetryListener,Guava Retryer在每次重试之后会自动回调监听器,并且支持注册多个监听。

@Slf4j
class DiyRetryListener<Boolean> implements RetryListener {
    @Override
    public <Boolean> void onRetry(Attempt<Boolean> attempt) {
        log.info("重试次数:{}",attempt.getAttemptNumber());
        log.info("距离第一次重试的延迟:{}",attempt.getDelaySinceFirstAttempt());
        if(attempt.hasException()){
            log.error("异常原因:",attempt.getExceptionCause());
        }else {
            System.out.println("正常处理结果:{}" + attempt.getResult());
        }
    }
}

定义监听器之后,需要在Retryer中进行注册。

        Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
                .retryIfResult(Predicates.<Boolean>isNull()) // callable返回null时重试
                .retryIfExceptionOfType(IOException.class) // callable抛出IOException重试
                .retryIfRuntimeException() // callable抛出RuntimeException重试
                .withStopStrategy(StopStrategies.stopAfterAttempt(3)) // 重试3次后停止
                .withRetryListener(new DiyRetryListener<Boolean>()) // 注册监听器
                .build();

小结

Guava Retryer不光在重试策略上支持多种选择,并且将业务逻辑的处理放在Callable中,和重试处理逻辑分开,实现了解耦,这比小黑自己去写循环处理要优秀太多啦,Guava确实强大。

到此这篇关于Guava Retryer实现接口重试的示例的文章就介绍到这了,更多相关Guava Retryer 口重试 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • java 重试框架 sisyphus 入门介绍

    What is Sisyphus sisyphus综合了 spring-retry 和 gauva-retrying 的优势,使用起来也非常灵活. 为什么选择这个名字 我觉得重试做的事情和西西弗斯很相似. 一遍遍的重复,可能徒劳无功,但是乐此不疲. 人一定要想象西西弗斯的快乐.--加缪 其他原因 以前看了 java retry 的相关框架, 虽然觉得其中有很多不足之处.但是没有任何重复造轮子的冲动,觉得是徒劳无功的. 当然这段时间也看了 Netty 的接口设计,和 Hibernate-Valid

  • Java基于Guava Retrying实现重试功能

    在接口调用中由于各种原因,可能会重置失败的任务,使用Guava-Retrying可以方便的实现重试功能. 首先,需要引用Guava-Retrying的包 <dependency> <groupId>com.github.rholder</groupId> <artifactId>guava-retrying</artifactId> <version>2.0.0</version> </dependency>

  • Java编程Retry重试机制实例详解

    本文研究的主要是Java编程Retry重试机制实例详解,分享了相关代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下 1.业务场景 应用中需要实现一个功能: 需要将数据上传到远程存储服务,同时在返回处理成功情况下做其他操作.这个功能不复杂,分为两个步骤:第一步调用远程的Rest服务逻辑包装给处理方法返回处理结果:第二步拿到第一步结果或者捕捉异常,如果出现错误或异常实现重试上传逻辑,否则继续逻辑操作. 2.常规解决方案演化 1)try-catch-redo简单重试模式: 包装正

  • Java 重试框架 Sisyphus 配置的两种方式

    目录 1.函数式配置概览 1.1 默认配置 2.方法说明 2.1 condition 2.2 retryWaitContext 2.3 maxAttempt 2.4 listen 2.5 recover 2.6 callable 2.7 retryCall 3.接口的详细介绍 3.1 接口及其实现 3.2 用户自定义 3.3 sisyphus 注解 4.设计的规范 4.1 maven 引入 4.2 Retry 4.3 RetryWait 5.注解的使用 5.1 Proxy+CGLIB 5.2 S

  • Guava Retryer实现接口重试的示例

    目录 前言 Guava Retryer 引入依赖 快速开始 指数退避(Exponential Backoff) 斐波那契退避(Fibonacci Backoff) 重试监听器 小结 前言 小黑在开发中遇到个问题,我负责的模块需要调用某个三方服务接口查询信息,查询结果直接影响后续业务逻辑的处理: 这个接口偶尔会因网络问题出现超时,导致我的业务逻辑无法继续处理: 这个问题该如何解决呢?,小黑首先想到的就是重试嘛,如果失败了就再调用一次. 问题来了,如果又失败了呢?接着重试嘛.我们循环处理,比如循环5

  • RateLimit-使用guava来做接口限流代码示例

    本文主要研究的是RateLimit-使用guava来做接口限流的相关内容,具体如下. 一.问题描述 某天A君突然发现自己的接口请求量突然涨到之前的10倍,没多久该接口几乎不可使用,并引发连锁反应导致整个系统崩溃.如何应对这种情况呢?生活给了我们答案:比如老式电闸都安装了保险丝,一旦有人使用超大功率的设备,保险丝就会烧断以保护各个电器不被强电流给烧坏.同理我们的接口也需要安装上"保险丝",以防止非预期的请求对系统压力过大而引起的系统瘫痪,当流量过大时,可以采取拒绝或者引流等机制. 二.常

  • spring retry方法调用失败重试机制示例解析

    目录 前言 1.导入依赖 2.注解的使用 3.开启重试 补充,手动声明式重试: 前言 很多场景会用到重试的机制,比如:rpc服务调用失败重试,文件上传oss失败重试,http接口调用失败重试,支付回调失败重试等等,一切因为网络,非逻辑性错误等不确定因素引起的失败都可以加上重试的机制,来增强系统的健壮性,博主也处理过文件上传到第三方oss服务失败增加重试的事例,在这之前不知道spring有个spring-retry项目,所以采用的是限制次数的递归调用的方式来解决的. 现在我们来看看spring b

  • 微信公众平台接口开发入门示例

    本文实例讲述了微信公众平台接口开发入门示例.分享给大家供大家参考.具体如下: 微信公众平台的接口开发是一个现在比较常用的功能了,很多的人都会去了解一下微信公众平台一些简单开发应用,这里就来给大家介绍一个入门示例. 这段时间都在忙于微信公众号平台来发,现在已经接近尾声了,所以对于微信开发平台的接口如何使用,在这里也唠刀一两句. 微信平台的开发并不像你想像的那么难,无非就是数据的存取处理罢了,对于数据的存取,简单如留言板,存数据,我们通过表单向数据库提交数据以存入;取数据,通过查询语句从数据库取得,

  • python统计mysql数据量变化并调用接口告警的示例代码

    统计每天的数据量变化,数据量变动超过一定范围时,进行告警.告警通过把对应的参数传递至相应接口. python程序如下 #!/usr/bin/python # coding=utf-8 import pymysql as mdb import os import sys import requests import json tar_conn = mdb.connect(host='192.168.56.128',port=3306,user='xxx',passwd='xxx123',db='b

  • SpringBoot实现阿里云短信接口对接的示例代码

    前言 公司最近项目需要一个手机验证码的功能,任务确定后,倍感亚历山大,以为和第三方对接的都好麻烦,查阿里的API.网上大神写的博客,各种查之后才发现,简单的一塌糊涂,这里想说个问题,不知道其他的攻城狮们是不是和我一样的心里,刚接触个没做过的任务时,会一脸懵里的着急,无从下手的感觉,后来会了,就觉得简单的一*,在这里我说一下自己的体会,遇到任何难点,先理思路.任务拆分.逐个查资料,其实一套下来,就不会那种一脸懵逼的干着急... 所需条件 1.阿里云账户 2.开通云通讯中的短信服务 3.申请短信签名

  • Django-Scrapy生成后端json接口的方法示例

    网上的关于django-scrapy的介绍比较少,该博客只在本人查资料的过程中学习的,如果不对之处,希望指出改正: 以后的博客可能不会再出关于django相关的点: 人心太浮躁,个人深度不够,只学习了一些皮毛,后面博客只求精,不求多: 希望能坚持下来.加油! 学习点: 实现效果 django与scrapy的创建 setting中对接的位置和代码段 scrapy_djangoitem使用 scrapy数据爬取保存部分 数据库设计以及问题部分 django配置 实现效果: django与scrapy

  • Python实现http接口自动化测试的示例代码

    网上http接口自动化测试Python实现有很多,我也是在慕课网上学习了相关课程,并实际操作了一遍,于是进行一些总结,便于以后回顾温习,有许多不完善的地方,希望大神们多多指教! 接口测试常用的工具有fiddler,postman,jmeter等,使用这些工具测试时,需要了解常用的接口类型和区别,比如我用到的post和get请求,表面上看get用于获取数据post用于修改数据,两者传递参数的方式也有不一样,get是直接在url里通过?来连接参数,而post则是把数据放在HTTP的包体内(reque

  • C++调用C接口的实现示例

    C++调用C代码 一个C语言文件p.c #include <stdio.h> void print(int a,int b) { printf("这里调用的是C语言的函数:%d,%d\n",a,b); } 一个头文件p.h #ifndef _P_H #define _P_H void print(int a,int b); #endif C++文件调用C函数 #include <iostream> using namespace std; #include &q

  • vue中对接Graphql接口的实现示例

    说明: 本文是本人正在搞nestjs+graphql+serverless训练营中对Graphql讲解的基础知识点,可能有点前后没对接上,文中提到的Graphql授权也是下小节介绍的 一.对原来的Express返回Graphql项目修改 本章节使用的代码是express返回Graphql的代码,在使用前要先对代码进行基本的配置,比如处理跨域问题(Graphql本质也是发送一个http请求,既然是这样在vue项目中自然存在跨域的问题,需要先处理) 1.安装跨域的包,并且配置中间件 npm inst

随机推荐