redis相关异常之RedisConnectionExceptionRedisCommandTimeoutException
本文只是分析Letture类型的Redis 池化连接出现的连接超时异常、读超时异常问题。
1.RedisConnectionException
默认是10秒。
通过如下可以配置:
public class MyLettuceClientConfigurationBuilderCustomizer implements LettuceClientConfigurationBuilderCustomizer {@Overridepublic void customize(LettuceClientConfiguration.LettuceClientConfigurationBuilder clientConfigurationBuilder) {
// spring.redis.timeout等价clientConfigurationBuilder.commandTimeout(Duration.ofSeconds(100));
// 控制连接超时时间,默认是10秒ClientOptions.Builder builder = ClientOptions.builder().socketOptions(SocketOptions.builder().connectTimeout(Duration.ofMillis(10)).build());clientConfigurationBuilder.clientOptions(builder.build());}
}
2.RedisCommandTimeoutException
结论:抛出RedisCommandTimeoutException异常并非数据的写一定失败。只不过Redis内部超时逻辑跟写逻辑是异步处理,所以存在写成功后仍然抛出异常的情况。但是只要出现该异常必须得处理。
io.lettuce.core.RedisCommandTimeoutException: Command timed out after 2 second(s)
2.1.CommandHandler限制
CommandHandler是Netty中的handler。只不过其同时充当入栈、出栈handler。通俗点讲是Redis Write & Flush 数据到通道NioSocketChannel的必经之路。
AsyncCommand存在两大核心功能。其一是包裹用户数据,其二是实现了CompletableFuture接口,方便实现异步相关操作。
public class CommandHandler extends ChannelDuplexHandler implements HasQueuedCommands {private void writeSingleCommand(ChannelHandlerContext ctx, RedisCommand<?, ?, ?> command, ChannelPromise promise){if (!isWriteable(command)) {// 此处的就是判断是否存在超时的核心之处,借用CompletableFuture异步操作功能promise.trySuccess();// 此时说明数据写过程中超过用户设定的超时时间return;}...ctx.write(command, promise);// 数据正常写入,最终归宿是服务端}private static boolean isWriteable(RedisCommand<?, ?, ?> command) {return !command.isDone();}
}
public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {public boolean isDone() {return result != null;}
}
通过上述得知,只要CompletableFuture内部的变量result不为空,则就会按TimeoutException处理。所以result值何时赋值呢?
如下所示,CommandHandler处理完数据之后会通过如下方式设置result的值。
public class AsyncCommand<K, V, T> extends CompletableFuture<T> implements RedisCommand<K, V, T>, RedisFuture<T>,CompleteableCommand<T>, DecoratedCommand<K, V, T> {protected void completeResult() {if (command.getOutput() == null) {complete(null);} else if (command.getOutput().hasError()) {doCompleteExceptionally(ExceptionFactory.createExecutionException(command.getOutput().getError()));} else {// 成功发送则Output为字符串类型的“ok”complete(command.getOutput().get());}}
}
3.超时处理时机
3.1.阻塞等待超时
class FutureSyncInvocationHandler extends AbstractInvocationHandler {protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {try {Method targetMethod = this.translator.get(method);// CommandExpiryWriter#writerObject result = targetMethod.invoke(asyncApi, args);if (result instanceof RedisFuture<?>) {...long timeout = getTimeoutNs(command);//用户自定义的超时时间//command:AsyncCommand 利用CompletableFuture异步特性return LettuceFutures.awaitOrCancel(command, timeout, TimeUnit.NANOSECONDS);}return result;} catch (InvocationTargetException e) {throw e.getTargetException();}}
}
public class LettuceFutures {public static <T> T awaitOrCancel(RedisFuture<T> cmd, long timeout, TimeUnit unit) {try {//阻塞 其实内存调用的CompletableFuture#get阻塞方法。如果返回TimeoutExeception则说明AsyncCommand没有执行完毕,超时处理if (!cmd.await(timeout, unit)) {cmd.cancel(true);throw ExceptionFactory.createTimeoutException(Duration.ofNanos(unit.toNanos(timeout)));}return cmd.get();//这个方法还是调用CompletableFuture#get阻塞方法,但是该方法是根据内部属性result进行判断} catch (RuntimeException e) {throw e;} catch (ExecutionException e) {if (e.getCause() instanceof RedisCommandExecutionException) {throw ExceptionFactory.createExecutionException(e.getCause().getMessage(), e.getCause());}if (e.getCause() instanceof RedisCommandTimeoutException) {throw new RedisCommandTimeoutException(e.getCause());}throw new RedisException(e.getCause());} catch (InterruptedException e) {Thread.currentThread().interrupt();throw new RedisCommandInterruptedException(e);} catch (Exception e) {throw ExceptionFactory.createExecutionException(null, e);}}
}
如下伪代码所示:如果result不为null,则根据result类型抛出相关异常。否则通过timedGet在规定时间内阻塞等待,超时则抛出TimeoutException。
public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {public T get(long timeout, TimeUnit unit)throws InterruptedException, ExecutionException, TimeoutException {Object r;long nanos = unit.toNanos(timeout);return reportGet((r = result) == null ? timedGet(nanos) : r);}
}
3.2.定时任务超时处理
public class CommandExpiryWriter implements RedisChannelWriter {public <K, V, T> RedisCommand<K, V, T> write(RedisCommand<K, V, T> command) {potentiallyExpire(command, getExecutorService());//开启定时任务return writer.write(command);//DefaultEndPoint#write}private void potentiallyExpire(RedisCommand<?, ?, ?> command, ScheduledExecutorService executors) {long timeout = applyConnectionTimeout ? this.timeout : source.getTimeout(command);//用户自定义的超时时间if (timeout <= 0) {return;}// 从 timeout 时间之后开始执行定时任务。此时result值如果存在值则说明超时ScheduledFuture<?> schedule = executors.schedule(() -> {if (!command.isDone()) {command.completeExceptionally(ExceptionFactory.createTimeoutException(Duration.ofNanos(timeUnit.toNanos(timeout))));}}, timeout, timeUnit);if (command instanceof CompleteableCommand) {((CompleteableCommand) command).onComplete((o, o2) -> {if (!schedule.isDone()) {schedule.cancel(false);}});}}
}
重点:定时任务判断成功与否的唯一条件就是result是否存在值。情况1,如果此时result = ok表明数据已经在服务端落盘成功,但是同样会抛出RedisCommandTimeoutException。情况2,发送之前出现异常则result值为Throwable类型的异常值。
相关文章:
redis相关异常之RedisConnectionExceptionRedisCommandTimeoutException
本文只是分析Letture类型的Redis 池化连接出现的连接超时异常、读超时异常问题。 1.RedisConnectionException 默认是10秒。 通过如下可以配置: public class MyLettuceClientConfigurationBuilderCustomizer implements LettuceClientConfigurationBuilderCusto…...
Merge the squares! 2023牛客暑期多校训练营4-H
登录—专业IT笔试面试备考平台_牛客网 题目大意:有n*n个边长为1的小正方形摆放在边长为n的大正方形中,每次可以选择不超过50个正方形,将其合并为一个更大的正方形,求一种可行的操作使所有小正方形都被合并成一个n*n的大正方形 1…...
STM32 串口学习(二)
要用跳线帽将PA9与RXD相连,PA10与TXD相连。 软件设计 void uart_init(u32 baud) {//UART 初始化设置UART1_Handler.InstanceUSART1; //USART1UART1_Handler.Init.BaudRatebound; //波特率UART1_Handler.Init.WordLengthUART_WORDLENGTH_8B; //字长为 8 位数据格式U…...
点大商城V2_2.5.0 全开源版 商家自营+多商户入驻 百度+支付宝+QQ+头条+小程序端+unipp开源前端安装测试教程
安装测试环境:Nginx 1.20PHP7.2MySQL 5.6 修复了无法上传开放平台问题 安装说明: 1、上传后端目录至网站 2、导入提供的数据库文件 3、修改数据库配置文件根目录下config.php,增加数据库用户名和密码 4、网站后台直接访问网址ÿ…...
“深入理解SpringBoot:从入门到精通“
标题:深入理解Spring Boot:从入门到精通 摘要:本文将介绍Spring Boot的基本概念和核心特性,并通过示例代码演示如何使用Spring Boot构建一个简单的Web应用程序。 1. 简介 Spring Boot是一个开源的Java框架,旨在简化基…...
PCB绘制时踩的坑 - SOT-223封装
SOT-223封装并不是同一的,细分的话可以分为两种常用的封装。尤其是tab脚的属性很容易搞错。如果你想着用tab脚连接有属性的铺铜,来提高散热效率,那么你一定要注意你购买的器件tab脚的属性。 第一种如下图,第1脚为GND,第…...
Go语法入门 + 项目实战
👂 Take me Hand Acoustic - Ccile Corbel - 单曲 - 网易云音乐 第3个小项目有问题,不能在Windows下跑,懒得去搜Linux上怎么跑了,已经落下进度了.... 目录 😳前言 🍉Go两小时 🔑小项目实战 …...
QT控件通过qss设置子控件的对齐方式、大小自适应等
一些复杂控件,是有子控件的,每个子控件,都可以通过qss的双冒号选择器来选中,进行独特的样式定义。很多控件都有子控件,太多了,后面单独写一篇文章来介绍各个控件的子控件。这里就随便来几个例子 例如下拉列…...
基于java在线收银系统设计与实现
摘要 科技的力量总是在关键的地方改变着人们的生活,不仅如此,我们的生活也是离不开这样或者那样的科技改变,有的消费者没有时间去商场购物,那么电商和快递的结合让端口到消费者的距离不再遥远;有的房客因地域或者工作的…...
Linux--进程的新建状态
新建状态: 操作系统创建了进程的内核数据结构(task_struct、mm_struct、页表),但是页表没有创建映射关系,而且磁盘里的程序的代码和数据未加载到物理内存...
区间dp,合并石子模板题
设有 N 堆石子排成一排,其编号为 1,2,3,…,N。 每堆石子有一定的质量,可以用一个整数来描述,现在要将这 N 堆石子合并成为一堆。 每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,合并后与这两堆石子相邻的…...
C++代码格式化工具clang-format详细介绍
文章目录 clang-format思考代码风格指南生成您的配置运行 clang-format禁用一段代码的格式设置clang-format的设置预览 clang-format 我曾在许多编程团队工作过,这些团队名义上都有“编程风格指南”。该指南经常被写下来并放置在开发人员很少查看的地方。几乎在每种…...
CentOS 7安装PostgreSQL 15版本数据库
目录 一、何为PostgreSQL? 二、PostgreSQL安装 2.1安装依赖 2.2 执行安装 2.3 数据库初始化 2.4 配置环境变量 2.5 创建数据库 2.6 配置远程 2.7 测试远程 三、常用命令 四、用户创建和数据库权限 一、何为PostgreSQL? PostgreSQL是以加州大学…...
QGraphicsView实现简易地图2『瓦片经纬度』
前文链接:QGraphicsView实现简易地图1『加载离线瓦片地图』 地图采用GCJ02 Web 墨卡托投影,最小坐标:(-180.00000000000000,-85.05112877980655),最大坐标:(180.00000000000000,85.05112877980655)。瓦片地图单张图片像…...
医学图像重建—第一章笔记
序言 本书涵盖内容: 2D parallel beam imaging 2D fan beam imaging 3D parallel ray imaging 3D parallel plane imaging 3D cone beam imaging 算法包括:analytical method,iterative method 应用于: X-ray CT single photon…...
python-pytorch基础之神经网络分类
这里写目录标题 生成数据函数定义数据集定义loader加载数据定义神经网络模型测试输出是否为2个输入数据,输出结果 训练模型函数计算正确率 训练数据并保存模型测试模型准备数据加载模型预测对比结果 生成数据函数 import randomdef get_rectangle():widthrandom.ra…...
【C++ 程序设计】实战:C++ 变量实践练习题
目录 01. 变量:定义 02. 变量:初始化 03. 变量:参数传递 04. 变量:格式说明符 ① 占位符 “%d” 改为格式说明符 “%llu” ② 占位符 “%d” 改为格式说明符 “%f” 或 “%e” 05. 变量:字节数统计 06. 变量&a…...
微软对Visual Studio 17.7 Preview 4进行版本更新,新插件管理器亮相
近期微软发布了Visual Studio 17.7 Preview 4版本,而在这个版本当中,全新设计的扩展插件管理器将亮相,并且可以让用户可更简单地安装和管理扩展插件。 据了解,目前用户可以从 Visual Studio Marketplace 下载各式各样的 VS 扩展插…...
Kafka 入门到起飞 - Kafka怎么做到保障消息不会重复消费的? 消费者组是什么?
Kafka怎么做到避免消息重复消费的? 消费者组是什么? 消费者: 1、订阅Topic(主题) 2、从订阅的Topic消费(pull)消息, 3、将消费消息的offset(偏移量)保存在K…...
MongoDB 的增、查、改、删
Monogo使用 增 单条增加 db.member.insertOne({"name":"张三","age":18,"create":new Date()}) db.member.insert({"name":"李四1","age":18,"create":new Date()}) db.member.insertOne(…...
网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
MySQL中【正则表达式】用法
MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...
k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
服务器--宝塔命令
一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行! sudo su - 1. CentOS 系统: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...
基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
恶补电源:1.电桥
一、元器件的选择 搜索并选择电桥,再multisim中选择FWB,就有各种型号的电桥: 电桥是用来干嘛的呢? 它是一个由四个二极管搭成的“桥梁”形状的电路,用来把交流电(AC)变成直流电(DC)。…...
