一、延迟队列:

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

需求:

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. react 利用高阶组件给页面加上动画

    利用高阶组件给页面加上动画 并不想让所有的路由都有动画效果,只是想对指定的页面有路由切换效果,可以利用高阶组件来完成. # 定义高阶组件 import React, { Component } fro ...

  2. INFINI Labs 产品更新 | Easysearch 1.7.1发布

    INFINI Labs 产品又更新啦~,包括 Console,Gateway,Agent 1.23.0 和 Easysearch 1.7.1.此次版本重点修复历史遗留 Bug .网友们提的一些需求等. ...

  3. 让Easysearch运行在Kylin V10 (Lance)-aarch64上

    简介 本文主要介绍在国产操作系统 Kylin V10 (Lance)-aarch64 上安装单机版 Easysearch/Console/Agent/Gateway/Loadgen 系统配置 在安装之 ...

  4. PIC18 bootloader之RS485 bootloader

                                  了解更多关于bootloader 的C语言实现,请加我Q扣: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制b ...

  5. es6.6.1 java客户端 client基础操作

    1.引入jar包 <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId&g ...

  6. 使用allparis正交法,生成测试用例

    原文:https://www.csdn.net/tags/MtzaggysODU0NTItYmxvZwO0O0OO0O0O.html 介绍工具前先讲下理论知识正交法一般适用于多个输入条件且条件与条件之 ...

  7. python UI自动化,怎么在控制台调试代码?

    Chrom 控制台调试脚本 http://testingpai.com/article/1606720137383 可以在任意网页按 F12 进入开发者工具,选择 console 输入 JS 代码: ...

  8. Linux gpio子系统:gpio_direction_output 与 gpio_set_value的区别

    Linux gpio子系统:gpio_direction_output 与 gpio_set_value的区别 背景 最近改驱动程序,看到驱动代码中既有gpio_direction_output也有g ...

  9. todo高通Android UEFI中的LCD分析(1):启动流程分析

    # 高通Android UEFI中的LCD分析(1):启动流程 背景 之前学习的lk阶段点亮LCD的流程算是比较经典,但是高通已经推出了很多种基于UEFI方案的启动架构. 所以需要对这块比较新的技术进 ...

  10. ubuntu 安装 arm-none-eabi-gcc 的几种方式

    背景 这篇文章主要是为了解决 在 Linux 中 编译 能够在 裸机上 跑的 程序 目前许多嵌入式软件软件开发在Linux平台下进行,编译效率高很多,如今天所述的gcc-arm-none-eabi常适 ...