当前位置: 首页 > news >正文

接口请求重试八种方法

请求三方接口需要加入重试机制

在这里插入图片描述

一、循环重试

在请求接口的代码块中加入循环,如果请求失败则继续请求,直到请求成功或达到最大重试次数。

int retryTimes = 3;
for(int i = 0;i < retryTimes;i++){try{//请求接口的代码break;}catch(Exception e){//处理异常Thread.sleep(1000);//为了避免频繁请求,延迟1秒后重试}
}

二、使用递归结构

在请求接口的方法中调用自身,如果请求失败则继续调用,直到请求成功或达到最大重试次数。

public void requestWithRetry(int retryTimes){if(retryTimes <= 0){return;}try{//请求接口的代码}catch(Exception e){//处理异常Thread.sleep(1000);//延迟1秒后重试requestWithRetry(retryTimes - 1);}
}

三、使用网络工具内置重试机制

HTTP 客户端通常内置了一些重试机制,只需要在创建对应的客户端实例的时候进行配置即可,以 Apache HTTPClient 为例:

  • 4.5+ 版本:使用 HttpClients.custom().setRetryHandler() 方法来设置重试机制
  • 5.x 版本:使用 HttpClients.custom().setRetryStrategy() 方法来设置重试机制
CloseableHttpClient httpClient = HttpClients.custom().setRetryHandler(new DefaultHttpRequestRetryHandler(3,true)).build();CloseableHttpClient httpClient = HttpClients.custom().setRetryStrategy(new DefaultHttpRequestRetryStrategy(3,NEG_ONE_SECOND)).build();

Apache HTTPClient 还支持自定义重试策略,可以可以实现 HTTPRequestRetryHandler 接口(4.5 + 版本)或者 RetryStrategy 接口(5.x 版本)

CloseableHttpClient httpClient = HttpClients.custom().setRetryStrategy((response,executionCount,context) -> {if(executionCount > 3){//如果重试次数超过3次,则放弃重试return false;}if(status >= 500 && statusCode < 600){//如果遇到服务器错误状态码,则进行重试return true;}//其他情况不进行重试return false;}).build();

四、使用Spring Retry库

Spring Retry 提供了一组注解和工具类,可以方便地为方法添加重试功能。

<dependency><groupId>org.springframework.retry</groupId><artifactId>spring-retry</artifactId><version>1.3.1</version>
</dependency>

Spring Retry 的使用有两种方式,一种是使用 RetryTemplate 来显式调用需要重试的方法,一种实用注解来自动触发重试。

显式调用

RetryTemplate retryTemplate = new RetryTemplate();//配置重试策略
RetryPolicy retryPolicy = new SimpleRetryPolicy(3);
retryTemplate.setRetryPolicy(retryPolicy);//最大重试次数为 3 次//配置重试间隔策略
FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
backOffPolicy.setBackOffPeriod(1000);//重试间隔为 1 秒
retryTemplate.setBackOffPolicy(backOffPolicy);//使用RetryTemplate调用方法,执行需要重试的代码块
retryTemplate.execute((RetryCallback<Void,Exception>) context - >{//请求接口的代码return null;
});

Spring Retry 是一个提供重试机制的库,可以方便地在 Spring 项目中使用。使用 @Retryable 注解标记需要重试的方法,如果方法抛出异常则会自动重试。

@Retryable(value=Exception.class,maxAttempts=3)
public void request(){//请求接口的代码
}

在这里插入图片描述

注解调用:

①、配置重试切面

@Configuration
@EnableRetry //启用重试功能
public class RetryConfig{//配置其他bean
}

②、注解标记需要重试的方法

@Retryable(maxAttempts=3)//指定了最大重试次数为 3 次
public void request(){//请求接口代码
}

③、调用被标记的方法

@Autowired
private HttpService httpService;httpService.request();

springboot中使用:

①、启动类开启 Spring Retry 功能

@SpringBootApplication
@EnableRetry // 启用Spring Retry功能
public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}
}

②、进行重试的方法上添加 @Retryable指定了重试的异常类型、最大重试次数和重试间隔
@Backoff 注解用于指定重试间隔策略,delay 属性表示每次重试之间的间隔时间。在这个例子中,每次重试之间的间隔时间为 1 秒
@Retryable 注解只能标记在 public 方法上。如果需要在非 public 方法上使用重试功能,可以使用代理模式实现

@Service
public class MyService {@Retryable(value = {MyException.class}, maxAttempts = 3, backoff = @Backoff(delay = 1000))public void doSomething() {// 需要进行重试的方法逻辑}
}

如果需要在重试过程中进行一些特定的操作,比如记录日志、发送消息等,可以在重试方法中使用 RetryContext 参数,它提供了一些有用的方法来获取重试的上下文信息。

@Service
public class MyService {@Retryable(value = {MyException.class}, maxAttempts = 3, backoff = @Backoff(delay = 1000))public void doSomething(RetryContext context) {// 获取重试次数int retryCount = context.getRetryCount();// 获取上一次异常Throwable lastThrowable = context.getLastThrowable();// 记录日志、发送消息等操作// ...// 需要进行重试的方法逻辑}
}

五、使用Resilience4j库

提供了重试、熔断、限流等多种机制


<dependency><groupId>io.github.resilience4j</groupId><artifactId>resilience4j-spring-boot2</artifactId><version>1.7.0</version>
</dependency>

1、显式调用

//创建一个 RetryRegistry 对象
RetryRegistry retryRegistry = RetryRegistry.ofDefalults();//配置RetryRegistry实例,使用 RetryConfig 类来自定义 Retry 的配置,包括最大重试次数、重试间隔等
RetryConfig config = RetryConfig.custom().maxAttempts(3)//最大重试次数为 3 次.waitDuration(Duration.ofMillis(1000))//重试间隔为 1 秒.retryOnResult(response -> response.getStatus() == 500)//返回结果的状态码为 500 时进行重试.retryOnException(e -> e instanceof WebServiceException)//抛出 WebServiceException 异常时进行重试.retryExceptions(IOException.class, TimeoutException.class).ignoreExceptions(BusinessException.class, OtherBusinessException.class)//忽略 BusinessException 和 OtherBusinessException 异常.failAfterMaxAttempts(true).build();//使用 Retry 来装饰和执行需要进行重试的代码块
CheckedFunction0<String> retryableSupplier = Retry.decorateCheckedSupplier(retry, () -> {// 需要进行重试的代码return "result";
});

2、注解调用

//SpringBoot项目中使用@Retryable注解来标记需要重试的方法
@Service
public class MyService{//指定了重试的异常类型为MyException,最大重试次数3次,重试间隔1秒@Retryable(value={MyException.class},maxAttempts=3,backoff=@Backoff(delay = 1000))public void doSomething(){//需要进行重试的方法逻辑}
}

六、自定义重试工具类

①、自定义一个是实现了Callback抽象类的具体回调类

public abstract class Callback{//执行重试逻辑public abstract RetryResult doProcess();//RetryResult封装重试结果
}

②、封装重试结果

public class RetryResult{private Boolean isRetry;//是否需要进行重试private Object obj;//重试的结果对象//构造方法和getter方法省略public static RetryResult ofResult(Boolean isRetry, Object obj){return new RetryResult(isRetry, obj);}public static RetryResult ofResult(Boolean isRetry){return new RetryResult(isRetry, null);}
}

③、执行

public class RetryExecutor{//接收一个重试次数和一个回调对象public static Object execute(int retryCount,Callback callback){for(int curRetryCount = 0;curRetryCount < retryCount;curRetryCount++){RetryResult retryResult = callback.doProcess();if(retryResult.isRetry()){continue;}return retryResult.getObj();}return null;}
}

使用这个自定义的重试工具类时,只需要实现一个继承自 Callback 的回调类,并在其中实现具体的重试逻辑。然后,通过调用 RetryExecutor.execute() 方法来执行重试操作。这里直接用了一个匿名的实现:

//最大重试次数
int maxRetryCount = 3;
Object result = RetryExecutor.execute(maxRetryCount, new Callback() {@Overridepublic RetryResult doProcess() {// 执行需要重试的逻辑// 如果需要重试,返回 RetryResult.ofResult(true)// 如果不需要重试,返回 RetryResult.ofResult(false, result)}
});

七、并发框架异步重试

使用ThreadPoolExecutor把请求接口转换成一个异步任务,将任务放入线程池中异步执行
并发地重试请求接口。
可以在任务执行完成后,判断任务执行结果,如果失败则继续重试

int maxRetryTimes = 3;
int currentRetryTimes = 0;ThreadPoolExecutor executor = new ThreadPoolExecutor(10,//核心线程数10,//最大线程数0L,//空闲线程存活时间TimeUnit.MILLISECONDS,//时间的单位new LinkedBlockingQueue<>()//任务队列
);//任务
Callable<String> task = () -> {//请求接口的代码return "result";
}Future<String> future;
while(currentRetryTimes < maxRetryTimes){try{future = executor.submit(task);String result = future.get();//获取任务结果//判断任务执行结果,如果任务执行成功,则跳出循环;如果任务执行失败,则继续重试,直到达到最大重试次数break;}catch(Exception e){currentRetryTimes++;try{Thread.sleep(1000);}catch(InterruptedException ex){Thread.currentThread().interrupt();}}
}

八、消息队列重试

保证重试的可靠性,不会因为服务中断,而导致重试任务的丢失,可以引入消息队列
直接把消息投递到消息队列里,通过对消息的消费,来实现重试机制。

//指定了消费者的相关配置,包括消费者组和订阅的主题
@Component
@RocketMQMessageListener(topic="myTopic",consumerGroup="myConsumerGroup")
public class MyConsumer implements RocketMQListener<String>{@Overridepublic void onMessage(String message){try{//请求接口的代码}catch(Exception e){//处理异常//如果请求失败,创建一个 RocketMQ 的生产者,并将请求重新发送到消息队列中,等待下一次处理DefaultMQProducer producer = new DefaultMQProducer("myProducerGroup");producer.setNamesrvAddr("127.0.0.1:9876");try{producer.start();}catch(Exception ex){//处理异常}finally{producer.shutdown();}}}
}

【注意】

  • 合理设置重试次数和重试间隔时间,避免频繁地发送请求,同时也不要设置过大的重试次数,以免影响系统的性能和响应时间。
  • 考虑接口幂等性:如果请求是写操作,而且下游的服务不保证请求的幂等性,那么在重试时需要谨慎处理,可以通过查询等幂等的方式进行重试
  • 在重试过程中,需要考虑并发的问题。如果多个线程同时进行重试,可能会导致请求重复发送或请求顺序混乱等问题。可以使用锁或者分布式锁来解决并发问题。
  • 在处理异常时,需要根据具体的异常类型来进行处理。有些异常是可以通过重试来解决的,例如网络超时、连接异常等;而有些异常则需要进行特殊的处理,例如数据库异常、文件读写异常等。
  • 在使用重试机制时,需要注意不要陷入死循环。如果请求一直失败,重试次数一直增加,可能会导致系统崩溃或者资源耗尽等问题。
http://www.lryc.cn/news/288538.html

相关文章:

  • 【Linux 基础】常用基础指令(上)
  • 【RT-DETR有效改进】EfficientFormerV2移动设备优化的视觉网络(附对比试验效果图)
  • 《动手学深度学习(PyTorch版)》笔记4.4
  • Linux/Academy
  • windows .vscode的json文件配置 CMake 构建项目 调试窗口中文设置等
  • uniapp canvas做的刮刮乐解决蒙层能自定义图片
  • 利用SPI,结合数据库连接池durid进行数据服务架构灵活设计
  • 自动驾驶的决策层逻辑
  • 排序算法——希尔排序算法详解
  • Docker 容器内运行 mysqldump 命令来导出 MySQL 数据库,自动化备份
  • 【Java万花筒】数字信号魔法:Java库的魅力解析
  • 面试高频知识点:2线程 2.1 线程池 2.1.2 JDK中常见的线程池实现有哪些?
  • Azure Private endpoint DNS 记录是如何解析的
  • windows 安装sql server 华为云文档
  • 相同主题文章竟同时发表在同一个2区期刊 | 孟德尔随机化周报(1.10-1.16)
  • 网络安全的使命:守护数字世界的稳定和信任
  • 【七、centos要停止维护了,我选择Almalinux】
  • 架构师之路(十六)计算机网络(传输层)
  • python 调用SumatraPDF 静默打印PDF
  • nginx部署https域名ssl证书
  • Python学习之路-Django基础:HelloDjango
  • 完成NAT实验
  • uniapp 用web-view嵌套网页地址并传参
  • 时序数据库Tdengine 批量插入避免因为主键ts时间重复导致数据被覆盖掉
  • 【小白教程】幻兽帕鲁服务器一键搭建 | 支持更新 | 自定义配置
  • Chatgpt的崛起之路
  • java截取视频最后一帧照片作为封面
  • ARM Cortex-A 内核的运行模式切换
  • 分布式因果推断在美团履约平台的探索与实践
  • 254.【2023华为OD机试真题】-任务处理(贪心算法-JavaPythonC++JS实现)