Springboot实现重试机制
背景
研发工作中时常遇到要和其他服务对接,依赖对方能力的情况,最恶心的是对方提供的服务不稳定,时灵时不灵的,进而影响到自己功能的稳定性。万一发生了这种事,做为研发,咱该怎么办?通过容错直接抛出异常,让用户再试一次?那多low啊!一个优秀的研发很少将问题抛出去,一般都是自己尝试多遍且没办法之后,才会选择将问题反馈给用户。这就要求咱们的相关功能得有重试的能力。今天雷袭实践的课题就是在Springboot项目中实现接口自动重试机制。
代码实践
一、 纯手撸的重试机制
雷袭看到这个课题,第一时间想的是:“这么简单,还需要水个博客?写个try catch加while循环,不是分分钟解决问题吗? 以下是我的第一版代码:
public <T> T retryMethodLocal(Supplier<T> method, int maxRetries) {int retryCount = 0;while (retryCount <= maxRetries) {try {// 尝试执行方法return method.get();} catch (Exception e) {retryCount++;if (retryCount > maxRetries) {// 超过最大重试次数后抛出异常throw e;}System.out.println("第 " + retryCount + " 次重试...");}}return null; // 理论上不会到达这里}//测试方法,用于模拟一个不稳定的接口。当随机小数小于0.8时,抛错,public String testMethod(){StringBuilder builder = new StringBuilder("进入到testMethod方法");if (date != null){builder.append(",与上一次的时间间隔为:" + ( new Date().getTime()-date.getTime()));}date = new Date();log.info(builder.toString());// 示例:随机失败double random = Math.random();if (random < 0.8) {log.error("调用失败 " + random);throw new RuntimeException("调用失败 " + random);}log.error("调用成功 " + random);return "成功";}
Controller方法如下:
@GetMapping("/retryOne")public Object retryOne() {return leixiRetryService.retryMethodLocal(leixiRetryService::testMethod, 5);}
通过浏览器访问链接:http://127.0.0.1:19200/leixi/retryOne , 以下是控制台信息:
根据控制台的日志可知,重试机制是生效的。
二、通过guava-retrying 实现重试
以上方法虽然能解决问题,但是它太原生了。像重试这样的基础机制,Springboot肯定提供了相关的能力或组件,咱们完全不用自己写。在咨询了同事后,我又剽来了一种常用的方法,实现如下:
pom.xml增加依赖:
<dependency><groupId>com.github.rholder</groupId><artifactId>guava-retrying</artifactId><version>2.0.0</version></dependency>
service层添加方法:
public <T> T retryMethodByRetryer(Supplier<T> method, Integer maxRetries, Integer waitTime) {Retryer<T> retryer = RetryerBuilder.<T>newBuilder()//.retryIfResult(result -> !result.equals("成功")) //还可以通过返回结果判定是否重试.retryIfException().withWaitStrategy(WaitStrategies.fixedWait(waitTime, TimeUnit.MILLISECONDS)).withStopStrategy(StopStrategies.stopAfterAttempt(maxRetries)).withRetryListener(new RetryListener() {@Overridepublic <V> void onRetry(Attempt<V> attempt) {log.info("第【{}】次重试,距离首次调用已过【{}】ms", attempt.getAttemptNumber(),attempt.getDelaySinceFirstAttempt());}}).build();try {return retryer.call(method::get);} catch (RetryException | ExecutionException e) {log.error(">>> 重试多次,远程获取批量报告文档url失败 <<<", e);}return null ;}
Controller层增加方法:
@GetMapping("/retryTwo")public Object retryTwo() {return leixiRetryService.retryMethodByRetryer(() -> leixiRetryService.testMethod(), 5, 100);}
通过浏览器访问链接:http://127.0.0.1:19200/leixi/retryTwo , 以下是控制台信息:
该方法相比于第一版就优雅了很多,它通过封装的重试对象,可以精准的捕获到调用的次数,间隔时间,调用结果,还可以手动设置调用间隔,对于触发调用的条件也更加灵活。
三、 通过spring-retry实现重试
除了上述方法,Spring 还提供了一种重试策略,通过注解来实现,代码如下:
添加pom依赖:
<!-- 重试 --><dependency><groupId>org.springframework.retry</groupId><artifactId>spring-retry</artifactId></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.6</version></dependency>
Application.java中添加重试注解:@EnableRetry
Service层添加方法:
@Retryable(maxAttempts = 5, backoff = @Backoff(value = 100L, multiplier = 1.5))public String retryByTarget() {return testMethod();}
Controller中增加方法:
@GetMapping("/retryThree")public Object retryThree() {return leixiRetryService.retryByTarget();}
通过浏览器访问链接:http://127.0.0.1:19200/leixi/retryThree , 以下是控制台信息:
相比于前两种方式,这种方法更加优雅,代码量更少,且通过注解的方式,可以很容易的对功能进行大批量的修改。请各位留意@Retryable中的@Backoff注解,它控制接口调用的间隔时间梯度递增,如第一次间隔100ms,第二次间隔100*1.5ms,第三次间隔100*1.5*1.5,以此类推,如此很好的避免了有故障的服务在短时间内接到大量重试调用,从而导致问题恶化的情况。
小记
要注意的是,配置了重试机制的功能,需要保证它在事务上是幂等的。即无论第一次执行成功与否,再执行第二次时,其结果都不会改变。多次执行的结果是一致的。
雷袭很喜欢在工作中捕捉到能令自己惊艳的东西,比较各种工具/方法的不同实现方式,以增长见闻,提升眼界。每每发现到自己又有新的发现,总是欣喜莫名,程序员的乐趣,不外如是。
相关文章:
Springboot实现重试机制
背景 研发工作中时常遇到要和其他服务对接,依赖对方能力的情况,最恶心的是对方提供的服务不稳定,时灵时不灵的,进而影响到自己功能的稳定性。万一发生了这种事,做为研发,咱该怎么办?通过容错直接…...
CS内网渗透 ----【内网渗透实战】PsExec vs Telnet:建立IPC通道实现横向移动与域控上线全解析
目录 1. 什么是 PsExec? 2. 什么是 Telnet? 3. PsExec 与 Telnet 的区别及优势 3.1 主要区别 3.2 内网渗透中的优势 4. 实际案例 —— 使用 PsExec 上线域控主机 案例背景 操作步骤 案例效果 5. 总结 利用 PsExec 建立 IPC 通道 —— IPC 的定…...
第二十三天打卡
作业: 整理下全部逻辑的先后顺序,看看能不能制作出适合所有机器学习的通用pipeline 数据预处理 → 特征选择 → 降维 → 模型训练 import pandas as pd import numpy as np from sklearn.model_selection import train_test_split, GridSearchCV from sk…...
aardio - 将文本生成CSS格式显示
import win.ui; /*DSG{{*/ var winform win.form(text"aardio form";right759;bottom469) winform.add( button{cls"button";text"Button";left340;top130;right430;bottom180;z3}; edit{cls"edit";text"我是一串文本";lef…...
【漫话机器学习系列】256.用 k-NN 填补缺失值
用 k-NN 填补缺失值:原理、实现与应用 在实际的数据科学项目中,我们经常会遇到数据缺失(Missing Values)的问题。缺失值如果处理不当,不仅会影响模型训练,还可能导致最终结果偏差。 今天,我们…...
tomcat与nginx之间实现多级代理
准备工作 准备5台虚拟主机;至少准备3台虚拟主机; 设备1作为代理服务器;设备2与设备4作为处理静态资源请求服务器(使用nginx);设备3与设备5作为处理动态资源服务器(使用tomcat) 设…...
商业航天运动控制系统中的高可靠性芯片解决方案:挑战、策略与应用研究
摘要:随着商业航天领域的迅速发展,运动控制系统对芯片的可靠性提出了前所未有的挑战。本文深入探讨了商业航天运动控制系统中芯片可靠性面临的挑战,包括宇宙辐射效应、极端环境适应性及系统级可靠性保障等。同时,通过案例研究展示…...
[Java实战]Spring Boot 3 整合 Ehcache 3(十九)
[Java实战]Spring Boot 3 整合 Ehcache 3(十九) 引言 在微服务和高并发场景下,缓存是提升系统性能的关键技术之一。Ehcache 作为 Java 生态中成熟的内存缓存框架,其 3.x 版本在性能、功能和易用性上均有显著提升。本文将详细介绍…...
【Flask全栈开发指南】从零构建企业级Web应用
目录 🌟 前言🏗️ 技术背景与价值🚧 当前技术痛点🛠️ 解决方案概述👥 目标读者说明 🔍 一、技术原理剖析📊 核心概念图解💡 核心作用讲解🧩 关键技术模块说明⚖️ 技术选…...
使用docker安装clickhouse集群
1、简介 clickhouse 作为大数据场景中,实现快速检索的常用列式存储数据库,采用物理机部署,会在数据量大的场景中,物理机器存储达到阈值需要扩容,会带来比较大的问题,因此,使用docker部署clickho…...
佰力博科技准静态d33测试的注意事项
准静态d33测试是测量压电材料纵向压电应变常数的重要方法,其注意事项包括以下几个方面: 选择合适的测量设备 准静态d33测试需要使用专用的压电测试仪,如佰力博PEAI1000高精度压电分析仪、准静态d33测量仪或PCA1000压电陶瓷综合参数分析仪。这…...
iOS设备投屏Archlinux
我的iphone手机屏太小,我想把手机投到archlinux电脑上看。与是我就想找一个免费的软件。 UxPlay https://github.com/FDH2/UxPlay GPLv3,开源。原来只支持 AirPlay Mirror 协议,现在新增 支持来自 AirPlay 的纯音频 (Apple Los…...
VUE_UI组件的二次封装
属性和事件 <template><div><myInput a"1" b"2" c"3" change"() > {}"></myInput></div> </template>myInput.vue <template><div><el-input v-bind"$attrs">&…...
算法·KMP
KMP算法的思想 想要一次性遍历模板串 s 1 s_1 s1,不在匹配失败时重新开始遍历子串 s 2 s_2 s2,实现模板串不回退的效果。 KMP数组的理解 KMP数组有两种定义:一是匹配失败后,子串 s 2 s_2 s2应该回退的位置,一种…...
如何正确地写出单例模式
如何正确地写出单例模式 | Jarks Blog 枚举方式: public class SingletonObject {private SingletonObject() {}/*** 枚举类型是线程安全的,并且只会装载一次*/private enum Singleton {INSTANCE;private final SingletonObject instance;Singleton() {…...
Mac M系列 安装 jadx-gui
安装 Homebrew在终端中执行以下命令(需管理员密码): 安装 Homebrew(官方源) /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"国内用户可用镜像源加速&…...
水滴Android面经及参考答案
目录 static 关键字有什么作用,它修饰的方法可以使用非静态的成员变量吗? Java 中创建线程有几种方式? wait 和 sleep 的区别,如何打断 sleep? Java 垃圾回收的目的是什么,垃圾回收机制是怎样的? Java 的垃圾回收(GC)机制是如何工作的? 请解释 Java 内存模型(J…...
《猜拳游戏》
综合案例《猜拳游戏》 需求: 本游戏是一款单机游戏,人机交互 规则: 需要双方出拳:石头、剪刀、布 赢: 石头 → 剪刀剪刀 → 布布 → 石头 平: 两边出拳相等 输: … 实现: 选择对…...
Mysql索引优化
一、索引 1. 主键索引(Primary Index) 定义 主键索引是一种特殊的唯一索引,用于唯一标识表中的每一行数据。每个表最多有一个主键索引,且索引列不允许为 NULL,自动添加 UNIQUE 和 NOT NULL 约束。 特点:…...
Postgresql与openguass对比
背景介绍 PostgreSQL是世界上最先进的开源关系型数据库,以其强大的功能、稳定性和可扩展性著称。而openGauss是华为公司于2020年6月30日开源的数据库系统,内核基于PostgreSQL 9.2.4版本演进而来。值得注意的是,PostgreSQL 11.3版本拥有290个数…...
线程的概念和控制
自从20世纪60年代提出了进程的概念之后,操作系统一直以进程作为独立运行的基本单位。到了20世纪80年代,人们又提出了比进程更小的、能独立运行的基本单位——线程。提出线程的目的是试图提高系统并发执行的程度,从而进一步提高系统的吞吐量。…...
如何配置activemq,支持使用wss协议连接。
1、到阿里云申请一个证书,通过后下载jks证书。 2、配置activemq: 打开activemq安装目录中“conf/activemq.xml”,增加以下记录: <transportConnectors> <transportConnector name"wss" uri"…...
【言语】刷题3
front:刷题2 题干 超限效应介绍冰桶挑战要避免超限效应 B明星的作用只是病痛挑战的一个因素,把握程度才是重点,不是强化弱化明星作用,排除 A虽没有超限效应,但是唯一的点出“冰桶效应”的选项,“作秀之嫌…...
关于 ast: Babel AST 全类型总览
AST 的每个节点都有一个 type 字段,用来标识它的语法类型。 程序结构节点 type说明示例Program整个程序的根节点整体代码结构BlockStatement大括号代码块 {}if、function、for 等的主体ExpressionStatement表达式语句(如 a b;)EmptyStatem…...
STM32 内存
根据STM32的存储器映射机制,其32位地址总线可访问4GB逻辑地址空间(0x00000000-0xFFFFFFFF),但实际物理地址分配由芯片厂商定义。以下是STM32完整的地址映射结构及关键区域说明: 一、地址空间整体架构 4GB地址空间划分…...
图片的require问题
问题 <template><!--第一种方式--><img :src"require(/assets/${imageName})" style"width:100px;" /><!--第二种方式--><img :src"require(imageUrl)" style"width:100px;" /> </template><…...
关于 js:8. 反调试与混淆识别
一、常见反调试手段识别 1. debugger 死循环(阻塞调试器) 样例代码: while (true) {debugger; }原理: 每次执行到 debugger 语句,如果 DevTools 打开,将自动触发断点。 如果在死循环中,调试…...
深度Q网络(DQN)的基本概念
一、深度Q网络(DQN)的基本概念 深度Q网络(Deep Q-Network,DQN)是将强化学习中的Q学习(Q-Learning)与深度学习相结合的算法,由DeepMind在2013年提出,并在2015年发表于《Nature》杂志。它通过神经网络近似动作价值函数(Q函数),解决传统Q学习在高维状态空间下的计算难…...
uniapp+vue3中自动导入ref等依赖
前言: 在我们使用uni-appvue3创建项目,开发的过程中,老是需要导入我们的ref、onshow等,那么能不能自动导入,不用我们每个页面都写呢?是没问题的,这里让他的小帮手来帮你减轻负担:他就…...
合肥SMT贴片加工核心优势与工艺升级
内容概要 在电子制造领域,工艺精度与生产效率的平衡始终是企业关注的核心命题。本文将系统呈现合肥SMT贴片加工产业的技术演进图谱,为寻求制造升级的企业提供可落地的决策参考。 作为长三角电子制造集群的重要节点,合肥SMT贴片加工产业通过持…...
Ansible安装与核心模块实战指南
Ansible安装与核心模块实战指南 自动化运维入门:从安装到模块化任务配置 Ansible作为一款无代理自动化工具,通过模块化设计实现高效管理,尤其适用于快速部署、配置和维护大规模系统。本文将从安装、核心模块使用到实际案例,全面解析其核心功能与最佳实践。 一、Ansible安装…...
TDengine 做为 Spark 数据源
简介 Apache Spark 是开源大数据处理引擎,它基于内存计算,可用于批、流处理、机器学习、图计算等多种场景,支持 MapReduce 计算模型及丰富计算操作符、函数等,在大超大规模数据上具有强大的分布式处理计算能力。 通过 TDengine …...
Codeforces Round 997 (Div. 2)
A. Shape Perimeter 题目大意 给你一个m*m的正方形,再给你n个坐标表示每次在xy移动的距离(第一个坐标是初始位置正方形左下角),问路径图形的周长 解题思路 记录好第一次的位置之后一直累加最后求总移动距离的差值即可 代码实…...
WSL 安装 Debian 12 后,Linux 如何安装 nginx ?
在 WSL 的 Debian 12 中安装 Nginx 的步骤如下: 1. 更新系统软件包 sudo apt update && sudo apt upgrade -y2. 安装 Nginx sudo apt install nginx -y3. 管理 Nginx 服务 ▶ 启动 Nginx sudo service nginx start # 如果使用 systemd 可能需改用&…...
目标检测任务 - 数据增强
目标检测任务 - DETR : 数据预处理/数据增强 算法源码实例 import datasets.transforms as Tnormalize T.Compose([T.ToTensor(),T.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ])scales [480, 512, 544, 576, 608, 640, 672, 704, 736, 768, 800]…...
java的switch case
import java.util.Scanner;public class Hello {public static void main(String[] args) {Scanner in new Scanner(System.in);int type in.nextInt();switch(type){case 1:case 2:System.out.println("你好");break;case 3:System.out.println("晚上好"…...
基于亚博K210开发板——LCD触摸屏读取坐标数据测试
开发板 亚博K210开发板 实验目的 主要学习 K210 通过 I2C 读取触摸屏的坐标,并打印出来,显示在 LCD上。 实验准备 实验元件 LCD 显示屏触摸板 元件特性 K210 开发板自带 2.0 寸触摸屏,其实是 LCD 显示屏上贴一个触摸板组成…...
coze平台实现文生视频和图生视频(阿里云版)工作流
工作流全貌 开始 首先从入参开始: api_key:来自阿里云百炼平台,自行去申请 prompt:生成视频的文本提示词。支持中英文,长度不超过800个字符,每个汉字/字母占一个字符,超过部分会自动截断。 …...
python酒店健身俱乐部管理系统
目录 技术栈介绍具体实现截图系统设计研究方法:设计步骤设计流程核心代码部分展示研究方法详细视频演示试验方案论文大纲源码获取/详细视频演示 技术栈介绍 Django-SpringBoot-php-Node.js-flask 本课题的研究方法和研究步骤基本合理,难度适中…...
QtGUI模块功能详细说明,图标和光标(七)
目录 一.窗口和屏幕管理 二. 绘图和渲染 三. 图像处理 四. 字体和文本 五. 事件和输入处理 六. OpenGL 和硬件加速 七. 颜色和外观 八. 图标和光标 1、QIcon: 图标管理 1.1、QIcon 简介 1.2、图标的来源与创建 1.3、多分辨率与 DPI 支持 1.4、图标的状态管理 2、…...
【图像处理基石】如何入门OCR技术?
入门OCR(Optical Character Recognition,光学字符识别)技术需要结合理论学习、工具实践和项目实战,以下是分步骤的学习指南,适合零基础学习者: 一、明确OCR技术的核心概念 OCR的基本原理 核心流程…...
数据库知识沉浸式游戏化学习设计研究
数据库知识沉浸式游戏化学习设计研究 摘要: 本研究旨在设计一款以数据库知识为主题的沉浸式游戏化学习系统。通过对数据库知识体系的深入剖析,结合游戏化学习理论,构建了一个多层次、多任务的游戏架构。玩家在游戏过程中需完成构建数据库结构、编写 SQL 查询等任务来解锁关…...
大疆无人机
在大疆上云API中,DRC 链路通常指 Device-Cloud Remote Control Link(设备-云端远程控制链路),它是无人机(或设备)与云端服务之间建立的实时控制与数据传输通道,用于实现…...
撤回不了一点 v1.0.2,支持微信QQ钉钉飞书等消息防撤回
如今生活节奏快得飞起,社交软件和工作通讯软件成了咱日常交流的核心阵地。大家肯定都有过这些闹心事儿:和朋友聊得正嗨,对方突然撤回一条消息,好奇心瞬间爆棚,却怎么也看不到撤回的内容;工作群里关键信息刚…...
什么是Git?
“Git”是目前非常火、广泛使用的版本控制系统,尤其在软件开发领域中扮演着核心角色。 一、什么是Git?它到底是什么? Git 是一种版本控制系统(Version Control System, VCS)。它的主要作用是帮助开发者管理“代码的不…...
微信小程序 自定义图片分享-绘制数据图片以及信息文字
一 、需求 从数据库中读取头像,姓名电话等信息,当分享给女朋友时,每个信息不一样 二、实现方案 1、先将数据库中需要的头像姓名信息读取出来加载到data 数据项中 data:{firstName:, // 姓名img:, // 头像shareImage:,// 存储临时图片 } 2…...
langchain提示词的使用
一、概述 提示词是指向人工智能大模型提供的输入信息,通常包含关键词、问题或指令,可以引导大模型生成与用户期望相符的回应。我们在豆包,DeepSeek等大模型中输入的问题都可以认为一个简单的提示词,不过为了真正得到我们需要的结…...
C语言| extern的用法作用
C语言| 局部变量、全局变量 extern定义的变量,只对全局变量有用。 掌握extern的用法及其作用。extern主要用于在不同.c文件间扩展全局变量的作用范围。 扩展全局变量的使用范围,操作方法: 1 在一个文件内扩展全局变量的使用范围 全局变量…...
Rust 环境变量管理秘籍:从菜鸟到老鸟都爱的 dotenv 教程
前言 写代码的你,是否遭遇过这些灵魂拷问: “我现在在哪个环境?开发?测试?还是直接在生产线上裸奔?”“少写一个 .env,测试脚本在数据库里上演清空大法,客户当场破防。”“每次手动设置 RUST_ENV,命令敲到一半就开始怀疑人生,还怕输错一个字符引发灭世级事故。”别慌…...
Leetcode (力扣)做题记录 hot100(49,136,169,20)
力扣第49题:字母异位词分组 49. 字母异位词分组 - 力扣(LeetCode) 遍历数组,将每一个字符串变成char数组 然后排序,如果map里面有则将他的值返回来(key是排序好的字符串) class Solution {pu…...