一、延迟队列:

消息经过交换机分配到队列上之后,在到达指定的时间,才会被消费?

需求:

1、下单之后的30分钟,用户未支付,订单取消,回滚库存

2、新用户注册7天后,发送短信慰问,或者是用户生日发送短信祝福

业务事件触发之后进入一个时间间隔,消息在这个间隔量的节点上再执行

Java程序提供了一些定时任务的框架,可以调用Java程序实现

或者是消息中间件自己做的延迟队列

是使用程序解决还是用消息队列解决,取决于现实业务的考量

二、RabbitMQ的技术方案:

RabbitMQ没有延迟队列这样的功能提供

可以使用 TTL + DLX 组合实现延迟队列的效果

三、RabbitMQ代码实现:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/rabbit
http://www.springframework.org/schema/rabbit/spring-rabbit.xsd">
<!--加载配置文件-->
<context:property-placeholder location="classpath:rabbitmq.properties"/> <!-- 定义rabbitmq connectionFactory publisher-confirms="true" 消息发送可确认
publisher-returns="true"
-->
<rabbit:connection-factory id="connectionFactory" host="${rabbitmq.host}"
port="${rabbitmq.port}"
username="${rabbitmq.username}"
password="${rabbitmq.password}"
virtual-host="${rabbitmq.virtual-host}"
publisher-confirms="true"
publisher-returns="true"
/>
<!--定义管理交换机、队列-->
<rabbit:admin connection-factory="connectionFactory"/> <!--定义rabbitTemplate对象操作可以在代码中方便发送消息-->
<rabbit:template id="rabbitTemplate" connection-factory="connectionFactory"/> <!--
延迟队列
1、定义正常的交换机和队列
2、定义死信的交换机和队列
3、绑定,并设置正常过期时间为30分钟 delay
--> <!-- 正常 -->
<rabbit:queue id="delay-regular-Q" name="delay-regular-Q">
<rabbit:queue-arguments>
<!-- 绑定分配死信-->
<entry key="x-dead-letter-exchange" value="delay-dead-X" />
<entry key="x-dead-letter-routing-key" value="dlx.order.cancel"/> <!-- TTL超时限定 -->
<entry key="x-message-ttl" value="10000" value-type="java.lang.Integer" />
</rabbit:queue-arguments>
</rabbit:queue> <rabbit:topic-exchange name="delay-regular-X" >
<rabbit:bindings>
<rabbit:binding pattern="order.#" queue="delay-regular-Q"/>
</rabbit:bindings>
</rabbit:topic-exchange> <!-- 死信 -->
<rabbit:queue id="delay-dead-Q" name="delay-dead-Q" />
<rabbit:topic-exchange name="delay-dead-X" >
<rabbit:bindings>
<rabbit:binding pattern="dlx.order.#" queue="delay-dead-Q"/>
</rabbit:bindings>
</rabbit:topic-exchange>
</beans>

测试类编写发送一条消息:

    @Test
public void delayTest() {
//
rabbitTemplate.convertAndSend(
"delay-regular-X",
"order.info",
"延迟队列测试 。。。。 在死信队列查看此消息 ");
}

消费者服务编写延迟队列的监听器

注意这个监听器是监听死信队列的

package cn.dzz.rabbitmq.listener;

import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener;
import org.springframework.stereotype.Component; import java.nio.charset.StandardCharsets;
@Component
public class DelayListener implements ChannelAwareMessageListener {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
long deliveryTag = 0;
try { System.out.println(new String(message.getBody(), StandardCharsets.UTF_8)); // 处理业务逻辑
// todo... /**
*
* 根据接收的ID查询订单状态
* 判断状态是否为支付成功
* 判断状态是否为支付成功
* 取消订单, 回滚库存
*
*/ int i = 10 / 0; // 这个异常会被捕获,然后触发RabbitMQ一直让消息重新入列发送 // 业务签收
deliveryTag = message.getMessageProperties().getDeliveryTag(); channel.basicAck(deliveryTag, true); } catch (Exception exception) {
// exception.printStackTrace();
System.out.println("已经触发异常Catch 消息被拒绝 .... ");
channel.basicNack(deliveryTag, true, false); // 被拒绝的消息不再重回队列, 这样这个消息才会分配到死信队列中 }
}
}

监听器XML配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/rabbit
http://www.springframework.org/schema/rabbit/spring-rabbit.xsd">
<!--加载配置文件-->
<context:property-placeholder location="classpath:rabbitmq.properties"/> <!-- 定义rabbitmq connectionFactory -->
<rabbit:connection-factory id="connectionFactory" host="${rabbitmq.host}"
port="${rabbitmq.port}"
username="${rabbitmq.username}"
password="${rabbitmq.password}"
virtual-host="${rabbitmq.virtual-host}"/> <context:component-scan base-package="cn.dzz.rabbitmq.listener" /> <!--
定义监听器容器
acknowledge="manual" 默认就是none
-->
<rabbit:listener-container connection-factory="connectionFactory" auto-declare="true" acknowledge="manual">
<rabbit:listener ref="delayListener" queue-names="delay-dead-Q" />
</rabbit:listener-container> </beans>

消费者服务经过延迟后收到消息:

监听测试
延迟队列测试 。。。。 在死信队列查看此消息
已经触发异常Catch 消息被拒绝 ....

【RabbitMQ】11 深入部分P4 延迟队列的更多相关文章

  1. 【RabbitMQ 实战指南】一 延迟队列

    1.什么是延迟队列 延迟队列中存储延迟消息,延迟消息是指当消息被发送到队列中不会立即消费,而是等待一段时间后再消费该消息. 延迟队列很多应用场景,一个典型的应用场景是订单未支付超时取消,用户下单之后3 ...

  2. RabbitMQ 入门教程(PHP版) 延迟队列,延迟任务

    延迟任务应用场景 场景一:物联网系统经常会遇到向终端下发命令,如果命令一段时间没有应答,就需要设置成超时. 场景二:订单下单之后30分钟后,如果用户没有付钱,则系统自动取消订单. 场景三:过1分钟给新 ...

  3. RabbitMQ、RocketMQ、Kafka延迟队列实现

    延迟队列在实际项目中有非常多的应用场景,最常见的比如订单未支付,超时取消订单,在创建订单的时候发送一条延迟消息,达到延迟时间之后消费者收到消息,如果订单没有支付的话,那么就取消订单. 那么,今天我们需 ...

  4. C#实现rabbitmq 延迟队列功能

    最近在研究rabbitmq,项目中有这样一个场景:在用户要支付订单的时候,如果超过30分钟未支付,会把订单关掉.当然我们可以做一个定时任务,每个一段时间来扫描未支付的订单,如果该订单超过支付时间就关闭 ...

  5. RabbitMQ如何实现延迟队列?(转)

    什么是延迟队列 延迟队列存储的对象肯定是对应的延迟消息,所谓"延迟消息"是指当消息被发送以后,并不想让消费者立即拿到消息,而是等待指定时间后,消费者才拿到这个消息进行消费. 场景一 ...

  6. Spring Boot(十四)RabbitMQ延迟队列

    一.前言 延迟队列的使用场景:1.未按时支付的订单,30分钟过期之后取消订单:2.给活跃度比较低的用户间隔N天之后推送消息,提高活跃度:3.过1分钟给新注册会员的用户,发送注册邮件等. 实现延迟队列的 ...

  7. rabbitmq延迟队列demo

    1. demo详解 1.1 工程结构: 1.2 pom 定义jar包依赖的版本.版本很重要,rabbit依赖spring,两者必须相一致,否则报错: <properties> <sp ...

  8. 【RabbitMQ】一文带你搞定RabbitMQ延迟队列

    本文口味:鱼香肉丝   预计阅读:10分钟 一.说明 在上一篇中,介绍了RabbitMQ中的死信队列是什么,何时使用以及如何使用RabbitMQ的死信队列.相信通过上一篇的学习,对于死信队列已经有了更 ...

  9. rabbitmq 实现延迟队列的两种方式

    原文地址:https://blog.csdn.net/u014308482/article/details/53036770 ps: 文章里面延迟队列=延时队列 什么是延迟队列 延迟队列存储的对象肯定 ...

  10. C# RabbitMQ延迟队列功能实战项目演练

    一.需求背景 当用户在商城上进行下单支付,我们假设如果8小时没有进行支付,那么就后台自动对该笔交易的状态修改为订单关闭取消,同时给用户发送一份邮件提醒.那么我们应用程序如何实现这样的需求场景呢?在之前 ...

随机推荐

  1. 滚动条小实验 BOM时间操作

      <div class="top">我是吸顶div</div>     <p class="back">返回顶部</ ...

  2. 剑指Offer-59.按之字形顺序打印二叉树(C++/Java)

    题目: 请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推. 分析: 实际上是二叉树的层次遍历,只不过每一行 ...

  3. ETL工具-nifi干货系列 第十七讲 nifi Input Port&Out Port 实战教程

    1.端口(Port),包含输入端口(Input Port)和输出端口(Out Port ) 使用一个或多个处理组构建的数据流需要一种方式将处理组连接到其他数据流组件. 处理组和处理组之间可以通过使用端 ...

  4. 使用 JavaScript 脚本来进行复杂的查询改写

    有这么一个需求: 网关里怎样对跨集群搜索进行支持的呢?我想实现: 输入的搜索请求是 lp:9200/index1/_search 这个索引在 3 个集群上,需要跨集群检索,也就是网关能否改成 lp:9 ...

  5. NumPy 简单算术:加减乘除及其他运算

    简单算术 你可以直接在 NumPy 数组之间使用算术运算符 + - * /,但本节讨论了一个扩展,其中我们有函数可以接受任何类似数组的对象,如列表.元组等,并根据条件执行算术运算. 条件算术:意味着我 ...

  6. 如何使用 Dump 文件?

    引言 本文概述了使用 WinDbg 的一些必要步骤. 准备工作 第一步,你必须更改系统的配置使其能够生成 PDB 文件,包括 Release 版本.近期的 Visual C++ 编译器默认启用此配置, ...

  7. 数据分析---matplotlib模块的使用

    1.摘要 在数据可视化.统计绘图和图表生成领域,Python 被广泛使用,其中 Matplotlib 是一个极其重要的基础三方库.本博客旨在介绍 Python 及其三方库 Matplotlib 的详细 ...

  8. glog_bash:在bash中优雅输出日志

    介绍 官方仓库:https://github.com/GuoFlight/glog_bash .下载其中的glog_bash.sh即可. 这是专门用于bash脚本中的logger,名为glog_bas ...

  9. 20-Docker镜像制作

    查看镜像构建的历史 docker image history 26a5 #查看镜像26a5的构建历史 使用commit命令构建镜像 使用commit命令可以将容器构建成镜像. 将容器webserver ...

  10. python 无监督生成模型

    无监督生成模型在机器学习中扮演着重要角色,特别是当我们在没有标签数据的情况下想要生成新的样本或理解数据的内在结构时.一种流行的无监督生成模型是生成对抗网络(Generative Adversarial ...