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.mzph.cn/news/226324.shtml

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

相关文章

策略+工厂完成支付方式选择(微信/支付宝),简单实现

需求 传参String payType wechat 使用微信支付传参String payType ali 使用支付宝支付代码不允许出现if-else 思路 把支付当作一个行为&#xff0c;代码中当作一个接口&#xff0c;payService。2个实现类&#xff0c;分别是微信支付实现类WeChatPayServiceImpl&#xff0c…

4G无线工业级路由器在智能制造设备互联互通中的角色

随着工业技术的不断发展和进步&#xff0c;智能制造已经成为了现代制造业的重要趋势和发展方向。而在智能制造过程中&#xff0c;设备之间的互联互通是至关重要的一环。在这个过程中&#xff0c;4G无线工业级路由器扮演着重要的角色&#xff0c;它提供了稳定可靠的网络连接&…

c语言->浅学结构体

系列文章目录 文章目录 前言 ✅作者简介&#xff1a;大家好&#xff0c;我是橘橙黄又青&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;橘橙黄又青_C语言,函数,指针-CSDN博客 目的&#xff1a;学习结构体基础内容&am…

6.【自动驾驶与机器人中的SLAM技术】鲁邦核函数的含义和应用

目录 1. 给ICP和NDT配准添加柯西核函数1.1 代码实现 2. 将第1部分的robust loss引入IncNDTLO和LooselyLIO&#xff0c;给出实现和运行效果3. 从概率层面解释NDT残差和协方差矩阵的关系&#xff0c;说明为什么NDT协方差矩阵可以用于最小二乘4. 为LOAM like LO设计一个地面点云提…

从菜鸟到专业人士:来自真实 PRD 写作经验的 5 个改变游戏规则的产品管理课程

产品管理是一个复杂且具有挑战性的角色。PRD&#xff08;即产品需求文档&#xff09;就像构建产品的蓝图&#xff0c;可将其视为指导开发团队创造令人惊叹的产品的详细路线图。本文除了介绍产品经理如何写好PRD&#xff0c;也将进一步阐述产品经理应该学习哪些技能&#xff1f;…

玩转树莓派之系统安装篇

介绍 树莓派是树莓派基金会下的一个明星产品&#xff08;单板计算机&#xff09;&#xff0c;已经迭代到第五代了&#xff1b;它性能强大、开源、拓展性强、体积小&#xff0c;搞物联网开发的人基本都听说过这个玩意&#xff01;笔者手上刚好有一块4B的板子&#xff0c;让我们…

python封装执行cmd命令的方法

一、前置说明 在自动化时&#xff0c;经常需要使用命令行工具与系统进行交互&#xff0c;因此可以使用python封装一个执行cmd命令的方法。 二、代码实现 import subprocess import timefrom common.exception import RunCMDError from common.logger import loggerclass Cmd…

STM32储存器和总线构架

一、引言 本篇文章旨在介绍STM32小容量、中容量和大容量的储存器和系统构架&#xff0c;文中涉及到一些专有名词和概念较为抽象和陌生&#xff0c;建议读者能够查阅相关资料和知识加深了解。 二、正文 &#xff08;一&#xff09;、系统构架 在小容量、中容量和 大容量产品中…

在qemu平台使用gdb调试程序

1、使用gdb在qemu上调试程序 1.1、第一步&#xff1a;在qemu上运行程序并开启gdb server qemu-system-riscv64 -nographic -machine virt -m 128M -smp 1 -kernel …/bin/test.elf -s -S 1.2、第二步&#xff1a;使用gdb客户端连接gdb server -x&#xff1a;指定gdb的配置文件…

jmeter 压测需要的部分配置

修改jmeter 目录的bin目录下的jmeter.properties文件 解除KeepAlive设置 修改接口的高级中的实现和超时 解除httpclient4.retrycount前的注释符并将0修改为1 即修改为&#xff1a;httpclient4.retrycount1 解除httpclient4.idletimeout前的注释符并修改为合适间隔 即修改为…

创建型模式之工厂方法模式

一、概述 1、工厂方法模式&#xff1a;定义一个用于创建对象的接口&#xff0c;让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类 2、工厂方法模式&#xff1a;不再提供一个按钮工厂类来统一负责所有产品的创建&#xff0c;而是将具体的按钮创建过程交…

电子电工企业品牌网站建设的作用是什么

电子电工企业在市场中有较高的需求度&#xff0c;比如电子元件、电子产品等&#xff0c;这些都属于高信任度产品&#xff0c;对需求方来说&#xff0c;需要查看商家全部信息、包括资质、产品/服务内容、案例等&#xff0c;因此对电子电工企业来讲&#xff0c;需要贯通品牌路径&…

解决RuntimeError: CUDA error: invalid device ordinal

步骤 首先查看自己设备的cuda版本 #如下linux指令都可以&#xff0c;主要还是以nvidia-smi为主 nvidia-smi nvcc -V用的python版本是3.8 torch版本用的1.12.1cu113 torch网址&#xff1a;https://pytorch.org/get-started/previous-versions/ 安装完后发现出现如下问题&#…

前端路由钩子的神奇之处:你真的了解它们吗?(上)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

CSS 基础

文章目录 CSS 常见的属性CSS 常见样式行内样式内嵌样式导入样式 CSS 选择器标签选择器id选择器类选择器全局选择器属性选择器组合选择器 CSS 常见应用表格列表导航栏下拉菜单提示工具图片廊 CSS (Cascading Style Sheets&#xff0c;层叠样式表&#xff09;&#xff0c;是一种用…

数据库连接池Druid

在 Spring Boot 项目中&#xff0c;数据库连接池已经成为标配&#xff0c;然而&#xff0c;我曾经遇到过不少连接池异常导致业务错误的事故。很多经验丰富的工程师也可能不小心在这方面出现问题。 在这篇文章中&#xff0c;我们将探讨数据库连接池&#xff0c;深入解析其实现机…

【卡塔尔世界杯数据可视化与新闻展示】

卡塔尔世界杯数据可视化与新闻展示 前言数据获取与处理可视化页面搭建功能实现新闻信息显示详情查看登录注册评论信息管理 创新点结语 前言 随着卡塔尔世界杯的临近&#xff0c;对于足球爱好者来说&#xff0c;对比赛的数据分析和新闻报道将成为关注的焦点。本文将介绍如何使用…

openmediavault debian linux安装配置企业私有网盘(三 )——raid5与btrfs文件系统无损原数据扩容

一、适用环境 1、企业自有物理专业服务器&#xff0c;一些敏感数据不外流时&#xff0c;使用openmediavault自建NAS系统&#xff1b; 2、在虚拟化环境中自建NAS系统&#xff0c;用于内网办公&#xff0c;或出差外网办公时&#xff0c;企业内的文件共享&#xff1b; 3、虚拟化环…

jmeter配置使用(mac)

前言 这篇文件就是一个笔记&#xff0c;非mac用户不用看了&#xff0c;我这是换了mac&#xff0c;要用jmeter的倒腾。 一、下载 二、使用步骤 1.解压 tgz格式的直接用tar命令就行 tar -zxvf 包名2.启动 一种是进入解压包的bin目录启动 这种方式启动的就是命令框不能关闭&am…

正则表达式详解

什么是正则表达式 正则表达式&#xff0c;又称规则表达式&#xff0c;通常被用来检索、替换那些符合某个模式(规则)的文本。 正则表达式是对字符串操作的一种逻辑公式&#xff0c;就是用事先定义好的一些特定字符、及这些特定字符的组合&#xff0c;组成一个"规则字符串…