使用重试和回退机制确保 Spring 微服务中的 API 弹性

在当今的数字环境中,应用程序严重依赖外部 HTTP/REST API来实现各种功能。这些 API 通常会编排复杂的内部和外部 API 调用网络。这创建了一个依赖网络。因此,当依赖的 API 发生故障或停机时,面向主要应用程序的 API 需要熟练、优雅地处理这些中断。鉴于此,本文探讨了Spring 微服务中重试机制和回退方法的实现。具体来说,它强调了这些策略如何显着增强 API 集成可靠性并显着改善用户体验。

了解相关 API 故障

使用依赖于其他服务的 API 来成功执行的移动和 Web 应用程序面临着独特的挑战。例如,对依赖 API 的调用可能会因各种原因而失败,包括网络问题、超时、内部服务器错误或计划停机。因此,此类故障可能会损害用户体验、破坏关键功能并导致数据不一致。因此,实施策略来妥善处理这些故障对于维护系统完整性至关重要。

重试机制

作为主要解决方案,重试机制用于处理暂时性错误和临时问题。通过自动重新尝试 API 调用,此机制通常可以解决与短暂网络故障或临时服务器不可用相关的问题。重要的是,区分适合重试的场景(例如网络超时)和重试可能无效甚至有害的场景(例如业务逻辑异常或数据验证错误)至关重要。

重试策略

常见的方法包括:

  • 固定间隔重试:定期尝试重试

  • 指数退避:此策略涉及以指数方式增加重试之间的间隔,从而减少服务器和网络的负载。

此外,这两种方法都应该附带最大重试限制,以防止无限循环。此外,监控和记录每次重试尝试对于将来的分析和系统优化也很重要。

Spring 微服务中的重试和回退

我们可以通过两种方式来实现重试和回退方法。

1. 弹性4j

@Retry注解是一种声明式方式,旨在简化应用程序中重试逻辑的实现。该注释可在resilience4j 包中找到。通过将此注解应用于服务方法,Spring 在遇到指定类型的异常时自动处理重试过程。

下面是一个真实的实现例子。该方法调用 API 来提取用于承保贷款申请的局报告。如果此方法失败,整个贷款申请承保流程就会失败,从而影响消费应用程序,例如移动应用程序。所以我们用以下注释来注释这个方法@Retry:


@Override
@Retry(name = "SOFT_PULL", fallbackMethod = "performSoftPull_Fallback")
public CreditBureauReportResponse performSoftPull(SoftPullParams softPullParams, ErrorsI error) {CreditBureauReportResponse result = null;try {Date dt = new Date();logger.info("UnderwritingServiceImpl::performSoftPull method call at :" + dt.toString() + ", for loan acct id:" + softPullParams.getUserLoanAccountId());CreditBureauReportRequest request = this.getCreditBureauReportRequest(softPullParams);RestTemplate restTemplate = this.externalApiRestTemplateFactory.getRestTemplate("SOFT_PULL", error);HttpHeaders headers = this.getHttpHeaders(softPullParams);HttpEntity<CreditBureauReportRequest> entity = new HttpEntity<>(request, headers);long startTime = System.currentTimeMillis();String uwServiceEndPoint = "/transaction";String callUrl = String.format("%s%s", appConfig.getUnderwritingTransactionApiPrefix(), uwServiceEndPoint);ResponseEntity<CreditBureauReportResponse> responseEntity = restTemplate.exchange(callUrl, HttpMethod.POST, entity, CreditBureauReportResponse.class);result = responseEntity.getBody();long endTime = System.currentTimeMillis();long timeDifference = endTime - startTime;logger.info("Time taken for API call SOFT_PULL/performSoftPull call 1: " + timeDifference);} catch (HttpClientErrorException exception) {logger.error("HttpClientErrorException occurred while calling SOFT_PULL API, response string: " + exception.getResponseBodyAsString());throw exception;} catch (HttpStatusCodeException exception) {logger.error("HttpStatusCodeException occurred while calling SOFT_PULL API, response string: " + exception.getResponseBodyAsString());throw exception;} catch (Exception ex) {logger.error("Error occurred in performSoftPull. Detail error:", ex);throw ex;}return result;
}

我们可以在application.yml文件中定义其他属性,例如重试次数和重试之间的延迟:

resilience4j.retry:  configs:    default:      maxRetryAttempts: 3      waitDuration: 100    externalPartner:      maxRetryAttempts: 2      waitDuration: 1000  instances:    SOFT_PULL:      baseConfig: externalPartner

我们指定后备方法fallbackMethod = "performSoftPull_Fallback"。如果所有配置的重试尝试均失败,则调用此方法;在这种情况下,是两个。


public CreditBureauReportResponse performSoftPull_Fallback(SoftPullParams softPullParams, ErrorsI error, Exception extPartnerException) {logger.info("UnderwritingServiceImpl::performSoftPull_Fallback - fallback , method called for soft pull api call");CreditBureauReportResponse creditBureauReportResponse = null;String loanAcctId = softPullParams.getUserLoanAccountId();ApplicantCoBorrowerIdsMapping applicantCoBorrowerIdsMapping = this.uwCoBorrowerRepository.getApplicantCoBorrowerIdsMapping(loanAcctId);try {boolean result = this.partnerServiceExceptionRepository.savePartnerServiceException(applicantCoBorrowerIdsMapping.getApplicantUserId(),applicantCoBorrowerIdsMapping.getLoanId(), PartnerService.SOFT_PULL.getValue(), "GDS", null);if (!result) {logger.error("UnderwritingServiceImpl::performSoftPull_Fallback - Unable to save entry in the partner service exception table.");}LoanSubStatus loanSubStatus = LoanSubStatus.PARTNER_API_ERROR;result = this.loanUwRepository.saveLoanStatus(applicantCoBorrowerIdsMapping.getApplicantUserId(), applicantCoBorrowerIdsMapping.getLoanId(),IcwLoanStatus.INITIATED.getValue(), loanSubStatus.getName(), "Partner Service Down", null);if (!result) {logger.error("UnderwritingServiceImpl::performSoftPull_Fallback - Unable to update loan status, sub status when partner service is down.");}} catch (Exception ex) {logger.error("UnderwritingServiceImpl::performSoftPull_Fallback - An error occurred while calling softPullExtPartnerFallbackService, detail error:", ex);}creditBureauReportResponse = new CreditBureauReportResponse();UnderwritingApiError underwritingApiError = new UnderwritingApiError();underwritingApiError.setCode("IC-EXT-PARTNER-1001");underwritingApiError.setDescription("Soft Pull API error");List<UnderwritingApiError> underwritingApiErrors = new ArrayList<>();underwritingApiErrors.add(underwritingApiError);creditBureauReportResponse.setErrors(underwritingApiErrors);return creditBureauReportResponse;
}

​​​​​​​在这种情况下,后备方法返回与原始方法相同的响应对象。但是,我们还在数据存储中记录服务已关闭并保存状态,并将指示符转发回消费者服务方法。然后,该指示器会传递到消费移动应用程序,提醒用户有关我们合作伙伴服务的问题。一旦问题得到纠正,我们就会利用持久状态恢复工作流程并向移动应用程序发送通知,表明可以继续正常操作。

2. 弹簧重试

在这种情况下,我们需要安装spring-retry和spring-aspects包。对于与上面相同的方法,我们将其替换为@Retry注解:


@Retryable(retryFor = {HttpClientErrorException.class, HttpStatusCodeException.class, Exception.class}, maxAttempts = 2, backoff = @Backoff(delay = 100))
public CreditBureauReportResponse performSoftPull(SoftPullParams softPullParams, ErrorsI error) {

Spring 中的注释@Retryable允许我们指定应该触发重试的多个异常类型。我们可以在注释的 value 属性中列出这些异常类型。

@Retryable要为带注释的方法编写后备方法performSoftPull,我们将使用@Recover注释。当该方法performSoftPull由于指定的异常 ( HttpClientErrorException, HttpStatusCodeException, Exception) 而耗尽其重试尝试时,将调用此方法。该@Recover方法应该具有与该方法匹配的签名@Retryable,并添加异常类型作为第一个参数。


@Recover
public CreditBureauReportResponse fallbackForPerformSoftPull(HttpClientErrorException ex, SoftPullParams softPullParams, ErrorsI error) {// Fallback Implementation
}@Recover
public CreditBureauReportResponse fallbackForPerformSoftPull(HttpStatusCodeException ex, SoftPullParams softPullParams, ErrorsI error) {// Fallback Implementation
}@Recover
public CreditBureauReportResponse fallbackForPerformSoftPull(Exception ex, SoftPullParams softPullParams, ErrorsI error) {// Fallback Implementation
}

结论

总之,在 Spring 微服务中,通过重试机制和回退方法有效处理 API 故障对于构建健壮的、以用户为中心的应用程序至关重要。这些策略确保应用程序保持功能并提供无缝的用户体验,即使面对 API 故障也是如此。通过对暂时性问题实施重试并为更持久的故障定义回退方法,Spring 应用程序可以在当今互联的数字世界中提供可靠性和弹性。


作者:Amol Gote

更多技术干货请关注公号【云原生数据库

squids.cn,云数据库RDS,迁移工具DBMotion,云备份DBTwin等数据库生态工具。

irds.cn,多数据库管理平台(私有云)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/173174.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实验五 键盘按键与数码管显示(汇编与微机原理)

键盘按键与数码管显示 实验目的&#xff1a; 熟悉星研集成开发环境&#xff0c;掌握微机接口程序编写调试的基本方法。 掌握矩阵式键盘的工作原理及识别键盘按键的方法。 掌握8段数码管显示数字或字符的工作原理和它的使用方法。 掌握用8255扫描键盘及用8255刷新数码管显示…

优秀的员工成为公司的管理者之后,为何表现平庸?因为他们缺乏这些思维

在企业的实践中&#xff0c;我们发现平时能力最强的员工&#xff0c;在被提拔到管理层之后就慢慢变得平庸了&#xff0c;再也不是以前那个无所不能的“企业能人”了&#xff0c;甚至在一些事情的处理上还会有些笨拙。面对这种情况&#xff0c;我们一定会感觉很疑惑&#xff0c;…

Eclipse和Intellij IDEA的格式化代码快捷键

Eclipse和Intellij IDEA的格式化代码快捷键 eclipse的格式化快捷键是 Windows/Linux: Ctrl Shift F Mac: Cmd Shift F 按下这个组合键将会对当前编辑的代码进行格式化&#xff0c;使其符合你在Eclipse配置中定义的代码样式规范。你可以在Eclipse的偏好设置中配置代码格式化…

PC8231(CC/CV)5V/2.4A同步降压芯片 频率可调 限流欠压补偿

一&#xff0e;概述 PC8231 是一款同步降压转换器&#xff0c; 该转换器可驱动输出 2.4A 负载电流。 设计允许 PC8231 在 9V 到40V 宽输入电压范围内工作。通过将 COMP/EN 引脚逻辑电平拉低来实现外部关断功能&#xff0c;并进入待机模式。外部补偿使反馈控制环路具有良好的线…

JavaScript 原型,原型链的特点

JavaScript 的原型&#xff08;Prototype&#xff09;和原型链&#xff08;Prototype chain&#xff09;是 JavaScript 面向对象编程中的重要概念。 原型&#xff08;Prototype&#xff09; 在 JavaScript 中&#xff0c;每个对象都有一个原型对象&#xff0c;而这个原型对象…

CRM的智能招投标对企业有什么意义?

如今CRM系统的生态系统越来越壮大&#xff0c;这些工具的集成极大地丰富了CRM系统的应用场景&#xff0c;例如CRM系统集成企业微信等社交媒体为获客提供便利&#xff1b;再比如CRM集成ChatGPT提高邮件内容质量&#xff0c;对于经常接触招投标项目的业务人员来说&#xff0c;在C…

英特尔工作站:助力专业用户实现高效创作

原创 | 文 BFT机器人 英特尔工作站是由全球知名的英特尔公司设计和开发的一款计算平台。英特尔在工作站处理器领域将其产品分为性能型和移动型两类&#xff0c;它的诞生旨在满足专业用户在科学、工程、设计等领域对高性能计算的需求。英特尔工作站配备了最新的英特尔处理器、大…

EI期刊论文复现:考虑电动汽车可调度潜力的充电站两阶段市场投标策略程序代码!

本程序代码参考EI期刊论文《考虑电动汽车可调度潜力的充电站两阶段市场投标策略》&#xff0c;程序中基于历史数据评估可调度潜力&#xff0c;由联合报价模型确定节点边际电价&#xff0c;作为报价的参考&#xff0c;包含个体竞价模式&#xff0c;纳什博弈竞价&#xff0c;算例…

docker (简介、dcoker详细安装步骤)- day01

一、 为什么出现 Docker是基于Go语言实现的云开源项目。 Docker的主要目标是“Build&#xff0c;Ship and Run Any App,Anywhere”&#xff0c;也就是通过对应用组件的封装、分发、部署、运行等生命周期的管理&#xff0c;使用户的APP&#xff08;可以是一个WEB应用或数据库应…

Git远程仓库常用开发命令和理解

远程仓库 创建与合并分支 每次提交&#xff0c;Git都把它们串成一条时间线&#xff0c;这条时间线就是一个分支。截止到目前&#xff0c;只有一条时间线&#xff0c;在Git里&#xff0c;这个分支叫主分支&#xff0c;即master分支。 HEAD严格来说不是指向提交&#xff0c;而…

01.vue3大事件——项目初始化、技术介绍

后台数据管理系统 - 项目架构设计 在线演示&#xff1a;https://fe-bigevent-web.itheima.net/login 接口文档: https://apifox.com/apidoc/shared-26c67aee-0233-4d23-aab7-08448fdf95ff/api-93850835 接口根路径&#xff1a; http://big-event-vue-api-t.itheima.net 本项…

不能打电话的流量卡真的合法?一篇文章让你读懂这个问题!

不能打电话的流量卡合法吗&#xff1f;主要还是看你选择的流量卡类型了。 ​  市面上不能打电话的流量卡大致分为两种&#xff1a; 一种是不带手机号码的物联卡&#xff0c;企业设备采购的话是合法的&#xff0c;一般运营商在将物联卡发售给企业法人后&#xff0c;为每个企业…

工作流能实现自动化吗?应该用什么工具?

研究显示&#xff0c;CRM系统工作流自动化软件不仅能简化冗余的工作且不需要监控和指导就能提高员工的工作效率。企业需要工作流自动化软件吗&#xff1f;答案是肯定的&#xff0c;工作流自动化的好处有哪些&#xff1f; 为什么企业需要工作流自动化软件 每家企业都希望降本增…

项目启动出现白屏问题需要刷新后才能显示解决方案

Vue项目起始时出现白屏问题需要刷新后才能显示解决方案 项目加\<div>为什么页面会出现加载过慢问题&#xff1f;如何让页面变得更快懒加载静态资源缓存 Webpack解决方案减少Js冗余操作 项目加<div> 在vue中,我们常常会因为在template模板中没有加div标签而使得页面…

企业营销管理能够实现自动化吗?怎么做?

当今企业面临着越来越多的营销难题&#xff1a;如何有效培育潜在客户、如何提高营销活动的效果、如何优化营销资源的分配......企业的营销管理怎么做&#xff1f;或许CRM系统营销自动化会起到作用。 客户细分&#xff1a; 企业可以通过CRM的客户细分功能&#xff0c;根据客户…

C#文件夹基本操作(判断文件夹是否存在、创建文件夹、移动文件夹、删除文件夹以及遍历文件夹中的文件)

判断文件夹是否存在时&#xff0c;可以使用Directory类的Exists()方法或者DirectoryInfo类的Exists属性来实现。 一、判断文件夹是否存在 1.Directory类的Exists()方法 Exists()方法用于确定给定路径是否引用磁盘上的现有目录&#xff0c;语法如下。 public static bool Ex…

cesium雷达扫描圈

import * as Cesium from "cesium"; let lastStage""; // 圆扩散 export function showCircleScan(viewer,lon, lat,color,maxRadius,height) {var cartographicCenter new Cesium.Cartographic(Cesium.Math.toRadians(lon), Cesium.Math.toRadians(lat),…

内衣洗衣机和手洗哪个干净?最好用的迷你洗衣机

随着大家工作的压力越来越大&#xff0c;下了班之后只能想躺平&#xff0c;在洗完澡之后看着还需要手洗的内衣裤真的很头疼。有些小伙伴还有会攒几天再丢进去洗衣机里面一起&#xff0c;而且这样子是非常不好的&#xff0c;用过的内衣裤长时间不清洗容易滋生细菌&#xff0c;而…

单片机学习3——数码管

数码管&#xff0c;根据内部结构&#xff0c;可分为共阴极数码管和共阳极数码管。七段发光管加上一个小数点&#xff0c;共计8段。因此&#xff0c;我们对它编程的时候&#xff0c;刚好是用一个字节。 数码管的显示方式&#xff1a; 1&#xff09;静态显示&#xff1b; 2&…

QT网络协议知识体系(一)

//获取主机的名称和ip地址 //获取主机的所有信息