rabbitmq 延时队列
前言
某个产品 或者订单,有个有效期 过了有效期要取消
方法一 : 写个脚本,用crontab 定时扫描 改变状态 但是最低只能一分钟 ,不适合
方法二 : 用swoole得毫秒定时器,每秒钟去扫描表 明显占用资源 mysql受不了
方法三 :用rabbitmq延时队列 一开始将其丢入mq 死信队列,设置有效期,过时转发到其他队列,再启动一个消费者 消费 更改表状态
php 安装mq扩展
https://www.cnblogs.com/brady-wang/p/7662393.html
搭建mq服务
https://www.cnblogs.com/brady-wang/p/7660174.html
创建生产者和消费者
生产者 publish.php
<?php
header('Content-Type:text/html;charset=utf8;');
$time = 30;
$params = array(
'exchangeName' => 'test_cache_exchange'."_".$time,
'queueName' => 'test_cache_queue'."_".$time,
'routeKey' => 'test_cache_route'."_".$time,
);
$connectConfig = array(
'host' => '127.0.0.1',
'port' => 5672,
'login' => 'admin',
'password' => 'password',
'vhost' => '/'
);
//var_dump(extension_loaded('amqp'));
//
//exit();
try {
$conn = new AMQPConnection($connectConfig);
$conn->connect();
if (!$conn->isConnected()) {
//die('Conexiune esuata');
//TODO 记录日志
echo 'rabbit-mq 连接错误:', json_encode($connectConfig);
exit();
}
$channel = new AMQPChannel($conn);
if (!$channel->isConnected()) {
// die('Connection through channel failed');
//TODO 记录日志
echo 'rabbit-mq Connection through channel failed:', json_encode($connectConfig);
exit();
}
$exchange = new AMQPExchange($channel);
$exchange->setFlags(AMQP_DURABLE);//持久化
$exchange->setName($params['exchangeName']?:'');
$exchange->setType(AMQP_EX_TYPE_DIRECT); //direct类型
$exchange->declareExchange();
//$channel->startTransaction();
$queue = new AMQPQueue($channel);
$queue->setName($params['queueName']?:'');
$queue->setFlags(AMQP_DURABLE);
// 和普通生产者区别 在这 下面是过期时间和转发到的路由
$queue->setArguments(array(
'x-dead-letter-exchange' => 'delay_exchange',
'x-dead-letter-routing-key' => 'delay_route',
'x-message-ttl' => $time*1000,
));
$queue->declareQueue();
//绑定
$queue->bind($params['exchangeName'], $params['routeKey']);
} catch(Exception $e) {
}
//$num = mt_rand(100, 500);
$num = 1;
//生成消息
$exchange->publish(date("Y-m-d H:i:s"), $params['routeKey'], AMQP_MANDATORY, array('delivery_mode'=>2));
消费者 consumer.php
<?php
header('Content-Type:text/html;charset=utf8;');
$params = array(
'exchangeName' => 'delay_exchange',
'queueName' => 'delay_queue',
'routeKey' => 'delay_route',
);
$connectConfig = array(
'host' => 'localhost',
'port' => 5672,
'login' => 'admin',
'password' => 'password',
'vhost' => '/'
);
//var_dump(extension_loaded('amqp'));
//exit();
try {
$conn = new AMQPConnection($connectConfig);
$conn->connect();
if (!$conn->isConnected()) {
//die('Conexiuneesuata');
//TODO记录日志
echo 'rabbit-mq连接错误:', json_encode($connectConfig);
exit();
}
$channel = new AMQPChannel($conn);
if (!$channel->isConnected()) {
//die('Connectionthroughchannelfailed');
//TODO记录日志
echo 'rabbit-mqConnectionthroughchannelfailed:', json_encode($connectConfig);
exit();
}
$exchange = new AMQPExchange($channel);
$exchange->setFlags(AMQP_DURABLE);//声明一个已存在的交换器的,如果不存在将抛出异常,这个一般用在consume端
$exchange->setName($params['exchangeName'] ?: '');
$exchange->setType(AMQP_EX_TYPE_DIRECT);//direct类型
$exchange->declareExchange();
//$channel->startTransaction();
$queue = new AMQPQueue($channel);
$queue->setName($params['queueName'] ?: '');
$queue->setFlags(AMQP_DURABLE);
$queue->declareQueue();
//绑定
$queue->bind($params['exchangeName'], $params['routeKey']);
} catch (Exception$e) {
echo $e->getMessage();
exit();
}
function callback(AMQPEnvelope $message){
global $queue;
if ($message) {
$body = $message->getBody();
echo $body . PHP_EOL;
$queue->ack($message->getDeliveryTag());
} else {
echo 'nomessage' . PHP_EOL;
}
}
//$queue->consume('callback');第一种消费方式,但是会阻塞,程序一直会卡在此处
//第二种消费方式,非阻塞
$start = time();
while (true) {
$message = $queue->get();
if (!empty($message)) {
echo $message->getBody()."--失效时间 ".date("Y-m-d H:i:s"). PHP_EOL;
$queue->ack($message->getDeliveryTag());//应答,代表该消息已经消费
// $end = time();
// echo '<br>' . ($end - $start);
} else {
//echo'messagenotfound'.PHP_EOL;
}
}
执行推送 我改了不同时间推送,会生成不同的交换机 路由 队列,因为我用得是direct类型 要一一匹配

消费者开启
[root@localhost mq]# php consumer.php
2020-07-18 11:07:22--失效时间 2020-07-18 11:07:42
2020-07-18 11:07:22--失效时间 2020-07-18 11:07:42
2020-07-18 11:07:23--失效时间 2020-07-18 11:07:43
2020-07-18 11:07:23--失效时间 2020-07-18 11:07:43
2020-07-18 11:13:04--失效时间 2020-07-18 11:13:24 2020-07-18 11:21:00--失效时间 2020-07-18 11:21:10
2020-07-18 11:21:32--失效时间 2020-07-18 11:22:02
2020-07-18 11:21:32--失效时间 2020-07-18 11:22:02
2020-07-18 11:21:22--失效时间 2020-07-18 11:22:12
2020-07-18 11:21:23--失效时间 2020-07-18 11:22:13
2020-07-18 11:21:23--失效时间 2020-07-18 11:22:13
发现正常,都是我设置的事件过期后就到处理队列,在这里消费,处理逻辑即可
参考 https://www.cnblogs.com/Zhangcsc/p/11739754.html
https://blog.csdn.net/weixin_34310369/article/details/92262465?utm_medium=distribute.pc_relevant.none-task-blog-baidujs-2
rabbitmq 延时队列的更多相关文章
- java实现rabbitMQ延时队列详解以及spring-rabbit整合教程
在实际的业务中我们会遇见生产者产生的消息,不立即消费,而是延时一段时间在消费.RabbitMQ本身没有直接支持延迟队列功能,但是我们可以根据其特性Per-Queue Message TTL和 Dead ...
- IOS IAP 自动续订 之 利用rabbitmq延时队列自动轮询检查是否续订成功
启用针对自动续期订阅的服务器通知: - 官方地址: - https://help.apple.com/app-store-connect/#/dev0067a330b - 相关字段, 相关类型地址: ...
- RabbitMQ延时队列应用场景
应用场景 我们系统未付款的订单,超过一定时间后,需要系统自动取消订单并释放占有物品 常用的方案 就是利用Spring schedule定时任务,轮询检查数据库 但是会消耗系统内存,增加了数据库的压力. ...
- rabbitmq 延时队列 插件方式实现 每条消息都延时自己时间
上篇文章的延时是加到队列上的 通过死信过时推送 ,缺点就是不能每条消息定义自己的过时时间而且每次有新的过时时间,要新建一个交换机和队列 https://www.cnblogs.com/brady-wa ...
- RabbitMQ 延时消息队列
消息延时在日常随处可见: 1.订单创建10min之后不发起支付,自动取消. 2.30min定时推送一次邮件信息. 最常用到方式后台定时任务轮训,量小的时候可以使用,量大会出现数据读取会性能问题.Rab ...
- 基于rabbitMQ 消息延时队列方案 模拟电商超时未支付订单处理场景
前言 传统处理超时订单 采取定时任务轮训数据库订单,并且批量处理.其弊端也是显而易见的:对服务器.数据库性会有很大的要求,并且当处理大量订单起来会很力不从心,而且实时性也不是特别好 当然传统的手法还可 ...
- 面试官:RabbitMQ过期时间设置、死信队列、延时队列怎么设计?
哈喽!大家好,我是小奇,一位不靠谱的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新 一.前言 RabbitMQ我们经常的使用, ...
- 基于Redis实现延时队列服务
背景 在业务发展过程中,会出现一些需要延时处理的场景,比如: a.订单下单之后超过30分钟用户未支付,需要取消订单 b.订单一些评论,如果48h用户未对商家评论,系统会自动产生一条默认评论 c.点我达 ...
- 【转】基于Redis实现延时队列服务
背景 在业务发展过程中,会出现一些需要延时处理的场景,比如: a.订单下单之后超过30分钟用户未支付,需要取消订单b.订单一些评论,如果48h用户未对商家评论,系统会自动产生一条默认评论c.点我达订单 ...
随机推荐
- Ubuntu中的launcher
最近在ubuntu系统中下载了最新版的eclipse,在一个临时文件夹中解压了eclipse压缩包,然后打开eclipse,按平时常规做法,我在launcher里右键点击eclipse,选择“锁定到启 ...
- CTF-BugKu-加密
2020.09.12 恕我直言,上午做WeChall那个做自闭了,下午复习一下之前做过的. 做题 第一题 滴答~滴 https://ctf.bugku.com/challenges#滴答~滴 摩斯密码 ...
- 5.Topic与Partition
- SpringBoot框架:使用mybatis连接mysql数据库完成数据访问(二)
一.导入依赖包 1.在创建项目时勾选: 勾选SQL中的JDBC API.MyBatis Framework.MySQL Driver,创建项目后就会自动配置和引入这些包. 2.在pom.xml文件中添 ...
- php判断请求方式
1 /** 2 * 判断是否为get请求 3 * 4 * @return bool 5 */ 6 function is_get():bool 7 { 8 return $_SERVER['REQUE ...
- 虚拟机系列 | JVM类加载机制
本文源码:GitHub·点这里 || GitEE·点这里 一.类加载简介 类的加载机制是指把编译后的.class类文件的二进制数据读取到内存中,并为之创建一个java.lang.Class对象,用来封 ...
- Python爬取天气预报,Ta的城市开始降温了
前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理. PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行获取 python免费学习资 ...
- python-文本操作和二进制储存
0x01 open方法 r read w write a append b byte test.txt内容为 yicunyiye wutang 读取test.txt f = open('test.tx ...
- 常见消息中间件之RocketMQ
前言 RocketMQ是一款分布式.队列模型的消息中间件,由阿里巴巴自主研发的一款适用于高并发.高可靠性.海量数据场景的消息中间件.早期开源2.X版本名为MetaQ:2015年迭代3.X版本,更名为R ...
- @RestController和@Controller区别
1) 如果只是使用@RestController注解Controller,则Controller中的方法无法返回jsp页面,或者html,配置的视图解析器 InternalResourceViewRe ...