上篇文章的延时是加到队列上的 通过死信过时推送 ,缺点就是不能每条消息定义自己的过时时间而且每次有新的过时时间,要新建一个交换机和队列

https://www.cnblogs.com/brady-wang/p/13335104.html

rabbitmq还有种方式 要安装一个插件  rabbitmq-delayed-message-exchange

参考  https://www.cnblogs.com/brady-wang/p/13335243.html

实现是安装插件后交换机会多出一种 不过这种插件要安装 好像mq版本至少3.7

最终生产者生产时候 头部加上延时时间,那么他会存储在交换机里面,到时了才投递到对应队列

$exchange->setType('x-delayed-message'); //x-delayed-message类型

$exchange->publish($message, $params['routeKey'], AMQP_NOPARAM, ['headers'=>['x-delay'=> 1000*$i]]);
[root@localhost mq]# php delay_publish.php
发送时间:2020-07-18 14:05:25
i=3600,延迟3600秒
[root@localhost mq]# php delay_publish.php
发送时间:2020-07-18 14:05:28
i=3600,延迟3600秒
[root@localhost mq]# php delay_publish.php
发送时间:2020-07-18 14:05:30
i=3600,延迟3600秒
[root@localhost mq]# php delay_publish.php
发送时间:2020-07-18 18:52:21
i=3600,延迟3600秒
[root@localhost mq]# php delay_publish.php
发送时间:2020-07-18 18:52:48
i=3600,延迟3600秒
^[[A
[root@localhost mq]# php delay_publish.php
发送时间:2020-07-18 18:52:51
i=3600,延迟3600秒
^[[A[root@localhost mq]# php delay_publish.php
发送时间:2020-07-18 18:52:54
i=3600,延迟3600秒

  

[root@localhost mq]# php delay_comsumer.php
接收时间:2020-07-18 13:58:11
接收内容:{"order_id":1595051842,"i":5,"date":"2020-07-18 13:57:22"}
接收时间:2020-07-18 13:58:11
接收内容:{"order_id":1595051844,"i":4,"date":"2020-07-18 13:57:24"}
接收时间:2020-07-18 13:58:11
接收内容:{"order_id":1595051846,"i":3,"date":"2020-07-18 13:57:26"}
接收时间:2020-07-18 13:58:11
接收内容:{"order_id":1595051848,"i":2,"date":"2020-07-18 13:57:28"}
接收时间:2020-07-18 13:58:11
接收内容:{"order_id":1595051850,"i":1,"date":"2020-07-18 13:57:30"}

可以看到里面有4条消息延时了

代码 如下

生产者 delay_publish.php

<?php

//header('Content-Type:text/html;charset=utf-8;');

$params = array(
'exchangeName' => 'delayed_exchange_test',
'queueName' => 'delayed_queue_test',
'routeKey' => 'delayed_route_test',
); $connectConfig = array(
'host' => '127.0.0.1',
'port' => 5672,
'login' => 'admin',
'password' => 'password',
'vhost' => '/'
); //var_dump(extension_loaded('amqp')); 判断是否加载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->setName($params['exchangeName']);
$exchange->setType('x-delayed-message'); //x-delayed-message类型
/*RabbitMQ常用的Exchange Type有三种:fanout、direct、topic。       fanout:把所有发送到该Exchange的消息投递到所有与它绑定的队列中。       direct:把消息投递到那些binding key与routing key完全匹配的队列中。       topic:将消息路由到binding key与routing key模式匹配的队列中。*/
$exchange->setArgument('x-delayed-type','direct');
$exchange->declareExchange(); //$channel->startTransaction();
//RabbitMQ不容许声明2个相同名称、配置不同的Queue,否则报错
$queue = new AMQPQueue($channel);
$queue->setName($params['queueName']);
$queue->setFlags(AMQP_DURABLE);
$queue->declareQueue(); //绑定队列和交换机
$queue->bind($params['exchangeName'], $params['routeKey']);
//$channel->commitTransaction();
} catch(Exception $e) { } //for($i=5;$i>0;$i--){
$i = 3600;
//生成消息
echo '发送时间:'.date("Y-m-d H:i:s", time()).PHP_EOL;
echo 'i='.$i.',延迟'.$i.'秒'.PHP_EOL;
$message = json_encode(['order_id'=>time(),'i'=>$i,'date'=>date("Y-m-d H:i:s")]);
$exchange->publish($message, $params['routeKey'], AMQP_NOPARAM, ['headers'=>['x-delay'=> 1000*$i]]);
sleep(2);
//}
$conn->disconnect();

  

消费者 delay_consumer.php

<?php

//header('Content-Type:text/html;charset=utf8;');

$params = array(
'exchangeName' => 'delayed_exchange_test',
'queueName' => 'delayed_queue_test',
'routeKey' => 'delayed_route_test',
);
$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);//声明一个已存在的交换器的,如果不存在将抛出异常,这个一般用在consume端
$exchange->setName($params['exchangeName']);
$exchange->setType('x-delayed-message'); //x-delayed-message类型
/*RabbitMQ常用的Exchange Type有三种:fanout、direct、topic。       fanout:把所有发送到该Exchange的消息投递到所有与它绑定的队列中。       direct:把消息投递到那些binding key与routing key完全匹配的队列中。       topic:将消息路由到binding key与routing key模式匹配的队列中。*/
$exchange->setArgument('x-delayed-type','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 '接收时间:'.date("Y-m-d H:i:s", time()). PHP_EOL;
echo '接收内容:'.$body . PHP_EOL;
//为了防止接收端在处理消息时down掉,只有在消息处理完成后才发送ack消息
$queue->ack($message->getDeliveryTag());
} else {
echo 'no message' . PHP_EOL;
}
} //$queue->consume('callback'); 第一种消费方式,但是会阻塞,程序一直会卡在此处 //第二种消费方式,非阻塞
/*$start = time();
while(true)
{
$message = $queue->get();
if(!empty($message))
{
echo $message->getBody();
$queue->ack($message->getDeliveryTag()); //应答,代表该消息已经消费
$end = time();
echo '<br>' . ($end - $start);
exit();
}
else
{
//echo 'message not found' . PHP_EOL;
}
}*/ //注意:这里需要注意的是这个方法:$queue->consume,queue对象有两个方法可用于取消息:consume和get。前者是阻塞的,无消息时会被挂起,适合循环中使用;后者则是非阻塞的,取消息时有则取,无则返回false。
//就是说用了consume之后,会同步阻塞,该程序常驻内存,不能用nginx,apache调用。
$action = '2'; if($action == '1'){
$queue->consume('callback'); //第一种消费方式,但是会阻塞,程序一直会卡在此处
}else{
//第二种消费方式,非阻塞
$start = time();
while(true)
{
$message = $queue->get();
if(!empty($message))
{
echo '接收时间:'.date("Y-m-d H:i:s", time()). PHP_EOL;
echo '接收内容:'.$message->getBody().PHP_EOL;
$queue->ack($message->getDeliveryTag()); //应答,代表该消息已经消费
$end = time();
//echo '运行时间:'.($end - $start).'秒'.PHP_EOL;
//exit();
}
else
{
//echo 'message not found' . PHP_EOL;
}
}
}

  

rabbitmq 延时队列 插件方式实现 每条消息都延时自己时间的更多相关文章

  1. RabbitMQ 入门系列:10、扩展内容:延时队列:延时队列插件及其有限的适用场景(系列大结局)。

    系列目录 RabbitMQ 入门系列:1.MQ的应用场景的选择与RabbitMQ安装. RabbitMQ 入门系列:2.基础含义:链接.通道.队列.交换机. RabbitMQ 入门系列:3.基础含义: ...

  2. RabbitMQ延迟队列插件安装

    RabbitMQ延迟队列插件安装 一.下载插件 下载地址:https://www.rabbitmq.com/community-plugins.html 二.把下载的插件放到指定位置 下载的文件为zi ...

  3. rabbitmq 安装延时队列插件rabbitmq-delayed-message-exchange

    1.下载rabbitmq-delayed-message-exchange(注意版本对应) 链接:https://github.com/rabbitmq/rabbitmq-delayed-messag ...

  4. python 实现3-2 问候语: 继续使用练习 3-1 中的列表,但不打印每个朋友的姓名,而为每人打印一条消息。每条消息都包含相同的问候语,但抬头为相应朋友的姓名。

    names = ['linda', 'battile', 'emly'] print(names[0].title() + " " + "good moning!&quo ...

  5. RabbitMQ (八) 队列的参数详解

    代码中,我们通常这样声明一个队列: //声明队列 channel.QueueDeclare ( queue: QueueName, //队列名称 durable: false, //队列是否持久化.f ...

  6. RabbitMQ 入门系列:9、扩展内容:死信队列:真不适合当延时队列。

    系列目录 RabbitMQ 入门系列:1.MQ的应用场景的选择与RabbitMQ安装. RabbitMQ 入门系列:2.基础含义:链接.通道.队列.交换机. RabbitMQ 入门系列:3.基础含义: ...

  7. springboot项目整合rabbitMq涉及消息的发送确认,消息的消费确认机制,延时队列的实现

    1.引入maven依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactI ...

  8. RabbitMQ学习之延时队列

    原帖参考:http://www.cnblogs.com/telwanggs/p/7124687.html?utm_source=itdadao&utm_medium=referral http ...

  9. java实现rabbitMQ延时队列详解以及spring-rabbit整合教程

    在实际的业务中我们会遇见生产者产生的消息,不立即消费,而是延时一段时间在消费.RabbitMQ本身没有直接支持延迟队列功能,但是我们可以根据其特性Per-Queue Message TTL和 Dead ...

随机推荐

  1. 在 Flutter 中使用 TensorFlow Lite 插件实现文字分类

    如果您希望能有一种简单.高效且灵活的方式把 TensorFlow 模型集成到 Flutter 应用里,那请您一定不要错过我们今天介绍的这个全新插件 tflite_flutter.这个插件的开发者是 G ...

  2. mybatis的dao注入失败

    转载自https://blog.csdn.net/hanpenghu/article/details/83897618 springboot maven资源路径配置 resource路径配置, 解决m ...

  3. 刷题[RoarCTF 2019]Easy Java

    前置知识 WEB-INF/web.xml泄露 java web工程目录结构 Servlet访问URL映射配置 由于客户端是通过URL地址访问Web服务器中的资源,所以Servlet程序若想被外界访问, ...

  4. vue移动端记录列表滚动如何快速找到是哪个元素产生的滚动

    使用下面的代码粘贴到调试工具中运行一下,然后滚动页面,就可以看到是哪个元素产生的滚动了 function findscroller(element) { element.onscroll = func ...

  5. MySQL-Atlas--读写分离架构

    一.Atlas简介 Atlas是由 Qihoo 360公司Web平台部基础架构团队开发维护的一个基于MySQL协议的数据中间层项目.它在MySQL官方推出的MySQL-Proxy 0.8.2版本的基础 ...

  6. 大数据平台Hadoop集群搭建

    一.概念 Hadoop是由java语言编写的,在分布式服务器集群上存储海量数据并运行分布式分析应用的开源框架,其核心部件是HDFS与MapReduce.HDFS是一个分布式文件系统,类似mogilef ...

  7. Spring 注解形式AOP

    AOP 面向切面编程,通过预编译的方式,在运行期通过动态代理实现一种技术,AOP可实现业务与切面的逻辑分离,降低耦合度 一.注解形式的AOP Aspect:切面 Joinpoint:连接点,要拦截的方 ...

  8. Go-项目环境搭建

    Go-环境搭建两个参数 1. GOROOT  Go SDK安装目录,Go语言安装目录 2. GOPATH   项目根目录 Go-项目目录结构 goProjectName 项目根目录 bin 项目编译后 ...

  9. Python练习题 040:Project Euler 012:有超过500个因子的三角形数

    本题来自 Project Euler 第12题:https://projecteuler.net/problem=12 # Project Euler: Problem 12: Highly divi ...

  10. Python练习题 034:Project Euler 006:和平方与平方和之差

    本题来自 Project Euler 第6题:https://projecteuler.net/problem=6 # Project Euler: Problem 6: Sum square dif ...