Redis实现延迟队列

目录

一、什么是延时队列

二、延时队列的应用

三、举例说明

我的设计思想:


一、什么是延时队列


   延时队列相比于普通队列最大的区别就体现在其延时的属性上,普通队列的元素是先进先出,按入队顺序进行处理,而延时队列中的元素在入队时会指定一个延迟时间,表示其希望能够在经过该指定时间后处理或者是在某个时间进行处理。

二、延时队列的应用

  1. 12306 下单成功后,在半个小时内没有支付,自动取消订单。
  2. 如果订单一直处于某一个未完结状态时,及时处理关单,并退还库存。
  3. 用户下单外卖以后,距离超时时间还有 10 分钟时提醒外卖小哥即将超时。
  4. 外卖平台发送订餐通知,下单成功后 60s 给用户推送短信。
  5. 规定某个时间执行某个任务

三、举例说明

以下是我做项目时遇到的例子:  需求就是用户设定时间,到时间之后,系统自动执行某个任务

我的设计思想:

采用轮询的策略监听redis的key的值,将用户输入的时间在后端转换为一个时间戳,利用redis Zset的数据结构来存储,主要用来判断的就是时间戳,Zset是一个有序的集合,所有时间戳在前面的就是先要执行的事件,当然用时间戳来比较的话,就是从0到现在时间的时间戳来比较大小,如何redis存入的时间戳大于0且 小于当前时间戳就代表执行任务,否则就代表待执行


首先,封装了一个实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class DelayMessageVo implements Serializable {/*** 切记实例化*/private static final long serialVersionUID = -7671756385477179547L;/*** 消息 id*/private Integer id;/*** 消息内容*/private String content;/*** 消息到期时间*/private long expireTime;}

 对Redis进行操作

@Component
public class DelayQueueService {/*** key后面拼接当前机器的内网ip : 用于集群区分,解决集群出现的并发问题*/private static final String KEY = "delay_queue:" + getHostAddress();@Autowiredprivate RedisTemplate redisTemplate;/*** 添加消息到延时队列中*/public void put(DelayMessageVo message ) {redisTemplate.opsForZSet().add(KEY, message, message.getExpireTime());}/*** 从延时队列中删除消息*/public Long remove(DelayMessageVo message) {Long remove = redisTemplate.opsForZSet().remove(KEY, message);return remove;}/*** 获取延时队列中已到期的消息*/public List<DelayMessageVo> getExpiredMessages() {
//        1 : 获取到开始时间long minScore = 0;
//        2 : 获取当前时间long maxScore = System.currentTimeMillis();
//        3 : 获取到指定范围区间的数据列表Set<Object> messages = redisTemplate.opsForZSet().rangeByScore(KEY, minScore, maxScore);if (messages == null || messages.isEmpty()) {return Collections.emptyList();}
//        4 : 把对象进行封装,返回List<DelayMessageVo> result = new ArrayList<>();for (Object message : messages) {// 将 DelayMessageVo 对象转换为 JSON 字符串String jsonMessage = JSON.toJSONString(message);DelayMessageVo delayMessage = JSONObject.parseObject(jsonMessage, DelayMessageVo.class);result.add(delayMessage);}return result;}/*** 获取地址(服务器的内网地址)(内网ip)** @return*/public static String getHostAddress() {InetAddress localHost = null;try {localHost = InetAddress.getLocalHost();} catch (UnknownHostException e) {e.printStackTrace();}return localHost.getHostAddress();}
}

 轮询策略

    @Componentpublic class DelayMessageHandler {public static SimpleDateFormat dateTimeFormater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");@Autowiredprivate DelayQueueService delayQueue;@Autowiredprivate ExamineMapper examineMapper;/*** 处理已到期的消息(轮询)*/@Scheduled(fixedDelay = 60000)public void handleExpiredMessages() {String currentTime = getCurrentTime();
//      1 : 扫描任务,并将需要执行的任务加入到任务队列中List<DelayMessageVo> messages = delayQueue.getExpiredMessages();System.out.println(currentTime + " 待处理消息数量:" + messages.size());
//      2 : 开始处理消息if (!messages.isEmpty()) {for (DelayMessageVo message : messages) {
//                2.1 : 处理消息:先删除消息,获取当前消息是否已经被其他人消费Long remove = delayQueue.remove(message);if (remove > 0) {
//                2.2 : 开启线程异步处理消息:不让处理消息的时间阻塞当前线程new Thread(() -> {System.out.println(currentTime + " :" + message.getId() + " --> 消息开始处理");Integer id = message.getId();String content = message.getContent();if (content.equals("任务开始时间")){examineMapper.updateBeginExamineStatus(id);}else if (content.equals("任务结束时间")){examineMapper.updateFinishExamineStatus(id);}else if (content.equals("公告结束时间")){examineMapper.updatePublicityExamineStatus(id);}try {
//                      2.1.1 : 模拟睡眠3秒,任务的处理时间(实际可能会更长)Thread.sleep(3000);} catch (Exception e) {e.printStackTrace();}System.out.println(currentTime + " :" + message.getId() + " --> 消息处理结束");}).start();}}}}/*** 获取到的当前时分秒** @return*/public static String getCurrentTime() {String format = dateTimeFormater.format(new Date());return format;}}

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

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

相关文章

SQL、Jdbc、JdbcTemplate、Mybatics

数据库&#xff1a;查询&#xff08;show、select&#xff09;、创建&#xff08;create)、使用(use)、删除(drop)数据库 表&#xff1a;创建&#xff08;【字段】约束、数据类型&#xff09;、查询、修改&#xff08;alter *add&#xff09;、删除 DML&#xff1a;增加(inse…

2024年网络安全比赛--系统渗透测试(超详细)

一、竞赛时间 180分钟 共计3小时 二、竞赛阶段 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 1.在渗透机中对服务器主机进行信息收集&#xff0c;将服务器开启的端口号作为 Flag 值提交; 2.在渗透机中对服务器主机进行渗透&#xff0c;在服务器主机中获取服务器主机名称&#xff…

【自动化测试】web3py 连接 goerli

web3py 连接 goerli 直接使用库里方法 if __name__ __main__:from web3.auto.infura.goerli import w3w3.eth.get_balance(get_address_by_private_key(os.getenv("AAA_KEY")))error info: websockets.exceptions.InvalidStatusCode: server rejected WebSocket …

【算法刷题】每日打卡——动态规划(1)

背包问题 例题一 有 N件物品和一个容量是 V 的背包。每件物品只能使用一次。 第 i件物品的体积是 vi&#xff0c;价值是 wi。 求解将哪些物品装入背包&#xff0c;可使这些物品的总体积不超过背包容量&#xff0c;且总价值最大。 输出最大价值。 输入格式 第一行两个整数…

Threejs利用着色器编写动态飞线特效

一、导语 动态飞线特效是可视化数据地图中常见的需求之一&#xff0c;鼠标点击的区块作为终点&#xff0c;从其他区块飞线至点击区块&#xff0c;附带颜色变换或者结合粒子动画 二、分析 利用创建3点来构成贝塞尔曲线&#xff0c;形成线段利用着色器材质来按照线段以及时间…

NAS搭建WebDAV服务同步Zotero科研文献

文章目录 一、Zotero安装教程二、群晖NAS WebDAV设置三、Zotero设置四、使用公网地址同步Zotero文献库五、使用永久固定公网地址同步Zotero文献库 Zotero 是一款全能型 文献管理器,可以 存储、管理和引用文献&#xff0c;不但免费&#xff0c;功能还很强大实用。 ​ Zotero 支…

visual studio code 好用的插件

vscode-icons Better comments 该插件对不同类型的注释会附加了不同的颜色&#xff0c;更加方便区分&#xff0c;帮助我们在代码中创建更人性化的注释。 Error Lens Error Lens插件是一款可以检测你编写的代码的语法错误&#xff0c;并且会显示出对语法错误的诊断信息…

Mac搭建Frida逆向开发环境

一、简介 Frida是一种基于Python+JavaScript的动态分析工具,可以用于逆向开发、应用程序的安全测试、反欺诈技术等领域,本质是一种动态插桩技术。Frida主要用于在已安装的应用程序上运行自己的JavaScript代码,从而进行动态分析、调试、修改等操作,能够绕过应用程序的安全措…

【JavaEE】多线程案例 - 定时器

作者主页&#xff1a;paper jie_博客 本文作者&#xff1a;大家好&#xff0c;我是paper jie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 本文于《JavaEE》专栏&#xff0c;本专栏是针对于大学生&#xff0c;编程小白精心打造的。笔者用重金(时间和精力)打造&…

cesium 自定义贴图,shadertoy移植教程。

1.前言 cesium中提供了一些高级的api&#xff0c;可以自己写一些shader来制作炫酷的效果。 ShaderToy 是一个可以在线编写、测试和分享图形渲染着色器的网站。它提供了一个图形化的编辑器&#xff0c;可以让用户编写基于 WebGL 的 GLSL 着色器代码&#xff0c;并实时预览渲染结…

ajax和Axios快速入门

什么是ajax 概念&#xff1a; Asynchronous JavaScript And XML&#xff0c;异步的JavaScrip和XML&#xff0c;重点在异步。 作用&#xff1a; 1&#xff0c;数据交互&#xff0c;可以通过ajax给服务器发送请求&#xff0c;并获取服务器响应的数据。 2&#xff0c;异步交互&am…

LeetCode2961双模幂运算(相关话题:快速幂)

题目描述 给你一个下标从 0 开始的二维数组 variables &#xff0c;其中 variables[i] [ai, bi, ci, mi]&#xff0c;以及一个整数 target 。 如果满足以下公式&#xff0c;则下标 i 是 好下标&#xff1a; 返回一个由 好下标 组成的数组&#xff0c;顺序不限 。 示例 &…

力扣日记12.13-【二叉树篇】从中序与后序遍历序列构造二叉树

力扣日记&#xff1a;【二叉树篇】从中序与后序遍历序列构造二叉树 日期&#xff1a;2023.12.13 参考&#xff1a;代码随想录、力扣 106. 从中序与后序遍历序列构造二叉树 题目描述 难度&#xff1a;中等 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二…

OpenCV极坐标变换函数warpPolar的使用

学更好的别人&#xff0c; 做更好的自己。 ——《微卡智享》 本文长度为1702字&#xff0c;预计阅读4分钟 前言 前阵子在做方案时&#xff0c;得了几张骨钉的图片&#xff0c;骨科耗材批号效期管理一直是比较麻烦的&#xff0c;贴RFID标签成本太高&#xff0c;所以一般考虑还是…

深入解析Spring Boot集成MyBatis的多种方式

文章目录 1. 引言2. 传统的XML配置方式2.1 引入依赖2.2 配置数据源和MyBatis2.3 编写Mapper接口和XML映射文件2.4 使用Mapper 3. 注解配置方式3.1 引入依赖3.2 配置数据源和MyBatis3.3 编写Mapper接口3.4 使用Mapper 4. MyBatis动态SQL4.1 使用XML配置方式4.2 使用注解配置方式…

Qt/C++视频监控安卓版/多通道显示视频画面/录像存储/视频播放安卓版/ffmpeg安卓

一、前言 随着监控行业的发展&#xff0c;越来越多的用户场景是需要在手机上查看监控&#xff0c;而之前主要的监控系统都是在PC端&#xff0c;毕竟PC端屏幕大&#xff0c;能够看到的画面多&#xff0c;解码性能也强劲。早期的手机估计性能弱鸡&#xff0c;而现在的手机性能不…

Facebook广告系统结构

Facebook广告系统是一个复杂的大型系统&#xff0c;由多个组件和子系统相互配合工作&#xff0c;实现了广告的投放、拍卖、个性化推荐和效果评估等功能。下面小编讲讲Facebook广告系统的结构。 1、广告管理界面 广告管理界面是广告主与Facebook进行交互的入口&#xff0c;广告…

如何在Docker部署draw.io流程图软件并实现公网远程访问

前言 提到流程图&#xff0c;大家第一时间可能会想到Visio&#xff0c;不可否认&#xff0c;VIsio确实是功能强大&#xff0c;但是软件为收费&#xff0c;并且因为其功能强大&#xff0c;导致安装需要很多的系统内存&#xff0c;并且是不可跨平台使用。所以&#xff0c;今天给…

c语言链表的基本操作

在C语言中&#xff0c;链表是一种常见的数据结构&#xff0c;它由一系列节点组成&#xff0c;每个节点包含一个数据元素和一个指向下一个节点的指针。链表的基本操作包括创建、插入、删除和遍历等。 下面是一个简单的链表节点结构体定义&#xff1a; struct Node { int da…

Leaflet.Graticule源码分析以及经纬度汉化展示

目录 前言 一、源码分析 1、类图设计 2、时序调用 3、调用说明 二、经纬度汉化 1、改造前 2、汉化 3、改造效果 总结 前言 在之前的博客基于Leaflet的Webgis经纬网格生成实践中&#xff0c;已经深入介绍了Leaflet.Graticule的实际使用方法和进行了简单的源码分析。认…