- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
作为后端程序员,我们的日常工作就是调用一些第三方服务,将数据存入数据库,返回信息给前端。但你不能保证所有的事情一直都很顺利。像有些第三方API,偶尔会出现超时。此时,我们要重试几次,这取决于你的重试策略.
下面举一个我在日常开发中多次看到的例子:
public interface OutSource {
List<Integer> getResult() throws TimeOutException;
}
@Service
public class OutSourceImpl implements OutSource {
static Random random = new Random();
@Override
public List<Integer> getResult() {
//mock failure
if (random.nextInt(2) == 1)
throw new TimeOutException();
return List.of(1, 2, 3);
}
}
@Slf4j
@Service
public class ManuallyRetryService {
@Autowired
private OutSource outSource;
public List<Integer> getOutSourceResult(String data, int retryTimes) {
log.info("trigger time:{}", retryTimes);
if (retryTimes > 3) {
return List.of();
}
try {
List<Integer> lst = outSource.getResult();
if (!CollectionUtils.isEmpty(lst)) {
return lst;
}
log.error("getOutSourceResult error, data:{}", data);
} catch (TimeOutException e) {
log.error("getOutSourceResult timeout", e);
}
// 递归调用
return getOutSourceResult(data, retryTimes + 1);
}
}
@Slf4j
@RestController
public class RetryTestController {
@Autowired
private ManuallyRetryService manuallyRetryService;
@GetMapping("manually")
public String manuallyRetry() {
List<Integer> result = manuallyRetryService.getOutSourceResult("haha", 0);
if (!CollectionUtils.isEmpty(result)) {
return "ok";
}
return "fail";
}
}
看看上面这段代码,我认为它可以正常工作,当 retryTimes 达到4时,无论如何我们都会得到最终结果。但是你觉得写的好吗?优雅吗?下面我来介绍Spring中的一个组件: spring-retry ,我们不妨来试一试.
spring-retry 是Spring中的提供的一个重试框架,提供了注解的方式,在不入侵原有业务逻辑代码的方式下,优雅的实现重处理功能.
implementation 'org.springframework.boot:spring-boot-starter-aop''org.springframework.boot:spring-boot-starter-aop'
implementation 'org.springframework.retry:spring-retry'
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
添加 @EnableRetry 注解在入口的类上从而启用功能.
@SpringBootApplication
//看过来
@EnableRetry
public class TestSpringApplication {
public static void main(String[] args) {
SpringApplication.run(TestSpringApplication.class, args);
}
}
我们以前面的为例,看看怎么使用,如下面的代码:
public interface OutSource {
List<Integer> getResult() throws TimeOutException;
}
@Service
public class OutSourceImpl implements OutSource {
static Random random = new Random();
@Override
public List<Integer> getResult() {
//mock failure will throw an exception every time
throw new TimeOutException();
}
}
@Slf4j
@Service
public class RetryableService {
@Autowired
private OutSource outSource;
// 看这里
@Retryable(value = {TimeOutException.class}, maxAttempts = 3)
public List<Integer> getOutSourceResult(String data) {
log.info("trigger timestamp:{}", System.currentTimeMillis() / 1000);
List<Integer> lst = outSource.getResult();
if (!CollectionUtils.isEmpty(lst)) {
return lst;
}
log.error("getOutSourceResult error, data:{}", data);
return null;
}
}
@Slf4j
@RestController
public class RetryTestController {
@Autowired
private RetryableService retryableService;
@GetMapping("retryable")
public String manuallyRetry2() {
try {
List<Integer> result = retryableService.getOutSourceResult("aaaa");
if (!CollectionUtils.isEmpty(result)) {
return "ok";
}
} catch (Exception e) {
log.error("retryable final exception", e);
}
return "fail";
}
}
Service
层中的实现类中添加了 @Retryable
注解,实现了重试, 指定value是 TimeOutException
异常会进行重试,最大重试 maxAttempts
3次。 这一次,当我们访问 http://localhost:8080/retryable 时,我们将看到浏览器上的结果失败。然后在你的终端上看到:
INFO 66776 --- [nio-9997-exec-1] c.m.testspring.service.RetryableService : trigger timestamp:1668236840
INFO 66776 --- [nio-9997-exec-1] c.m.testspring.service.RetryableService : trigger timestamp:1668236841
INFO 66776 --- [nio-9997-exec-1] c.m.testspring.service.RetryableService : trigger timestamp:1668236842
ERROR 66776 --- [nio-9997-exec-1] c.m.t.controller.RetryTestController : retryable final exception
本文分享了 spring-retry 重试框架最基础的使用,可以无侵入业务代码进行重试。关于 spring-retry 更多的使用建议可以自己去官网 https://github.com/spring-projects/spring-retry 探索.
如果本文对你有帮助的话,请留下一个赞吧 欢迎关注个人公众号——JAVA旭阳 更多学习资料请移步: 程序员成神之路 。
最后此篇关于如何在SpringBoot中优雅地重试调用第三方API?的文章就讲到这里了,如果你想了解更多关于如何在SpringBoot中优雅地重试调用第三方API?的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
是否可以重试网络客户端请求?在奇怪的情况下,我的应用程序在尝试连接到 xml Web 服务时会抛出错误,但如果我重试,它就可以正常工作。我希望它在抛出错误之前重试 2 次,除非有人有更好的解决方案:)
我在一本书中找到了这段代码片段: int ival; // read cin and test only for EOF; loop is executed even if there are oth
是否可以使用 for lop 来设置对象的条件。如果该条件未通过测试(if 语句),则更改条件直到它通过测试?这是我的伪代码尝试,但我怀疑它是否有效: for (int i = 0; i < myAr
我有以下问题。我的主要 Activity 由一个 ListView 组成,其中填充了从 Web 服务获得的数据。首次加载主要 Activity 时,以防无法从网络检索数据,我想显示一个带有 2 个按钮
我有微服务应用程序。为了协作,每个服务都使用异步消息传递。我知道,spring data jpa 默认使用乐观锁。但是如果这种锁定不是由用户调用,而是由另一个服务调用的方法(在我的示例中有验证服务,可
我希望能够在 F# 中编写一个计算表达式,如果它抛出异常,它将能够重试操作。现在我的代码看起来像: let x = retry (fun() -> GetResourceX()) let y = re
是否可以在 NServiceBus 版本 3.2.2 中禁用重试? 使用以下配置,可以禁用重试: 但当线程数设置为 20 时则不会。在这种情况下,消息会重试两次: 这看起来很像
我在 failed_jobs 上有多个失败的作业。我尝试重新排队 MaxAttemptsExceededException 但总是失败。如何重试那里的工作类型? 注意:每次我通过 php artisa
下面的 sproc 尝试向表中插入一行并生成一个随机 ID,用于在相应表上进行 PK。与随机生成的 ID 的冲突在 catch 块中处理,在那里再次重试/调用该过程。现在,这需要很长时间并导致死锁,因
我试图实现代码以使用“mocha-retry”重试失败的测试以下是示例。 describe(retries,' retries-',function () { var self = this;
我正在尝试通过 Azure 数据工厂将数据从 Azure 数据湖存储插入到 Azure 表。 Azure Data Lake 文件中的数据与最终 Azure 表接收器的架构相同。 ADF 管道包含从
是http.RoundTripper在 Go 中基于 HTTP 状态代码(例如 429)实现 http GET 请求重试机制的正确位置? 它在某种程度上“感觉正确”( Go Playground )并
使用 spring reactive WebClient,我使用了一个 API,如果响应状态为 500,我需要使用指数退避重试。但是在 Mono 类中,我没有看到任何以 Predicate 作为输入参
我一直在尝试编写 react native 的快速入门指南,但一直收到此错误 There appears to be trouble with your network connection. Ret
我正在尝试使用从我们心爱的堆栈溢出中获取的 Retry Monad: type RetryBuilder(max, sleep : TimeSpan) = member x.Return(
使用 spring reactive WebClient,我使用了一个 API,如果响应状态为 500,我需要使用指数退避重试。但是在 Mono 类中,我没有看到任何以 Predicate 作为输入参
我有一个由 C#.NET 4.0 开发的两层 Windows 窗体应用程序。在这个应用程序中,我读取文件内容并在数据访问层中创建实体列表,并将其返回到 GUI 层以在 GridView 中显示。在我当
如果有人问过这个问题,我深表歉意,但我已经做了很多搜索,但还没有找到与我的问题类似的问题。 在我的应用程序中,我有一个密码更改页面,如果某人是新用户或重置了他/她的密码,该页面就会触发。 问题是,一旦
想知道为什么我的 promise 正在解决但试图重试。 var getResultsStream = url => Rx.Observable.onErrorResumeNext( Rx.O
假设我有以下 Promise 链: var result = Promise.resolve(filename) .then(unpackDataFromFile) .then(tra
我是一名优秀的程序员,十分优秀!