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

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. linux6.4内核由2.6升级成3.6

    安装CentOS 6.4之后,内核默认是2.6.32.由于docker需要3.0以上的内核,所以需要对内核进行升级. 1. 安装必要组件# yum -y install ncurses-devel # ...

  2. oracle之三手工完全恢复

    手工完全恢复 3.1 完全恢复:通过备份.归档日志.current log ,将database恢复到failure 前的最后一次commit状态. 3.2 完全恢复的步骤 1)restore: OS ...

  3. 第23课 - #error 和 #line 使用分析

    第23课 - #error 和 #line 使用分析 1. #error 的用法 (1)#error 是一个预处理器指示字,用于生成一个编译错误消息,这个消息最终会传递到编译器(gcc) 在思考这一点 ...

  4. Python中的相对路径的表示方法

    2020/6/3 举例: 现在 6-2.py 想使用 /data/lastfm-2k/user_artists.dat 因为 6-2.py 和 data 是同一级目录,所以正确的写法应该是:

  5. 容器云平台No.9~kubernetes日志收集系统EFK

    EFK介绍 EFK,全称Elasticsearch Fluentd Kibana ,是kubernetes中比较常用的日志收集方案,也是官方比较推荐的方案. 通过EFK,可以把集群的所有日志收集到El ...

  6. python爬取酷狗音乐

    url:https://www.kugou.com/yy/html/rank.html 我们随便访问一个歌曲可以看到url有个hash https://www.kugou.com/song/#hash ...

  7. Ubuntu16.04+Tensorflow+CUDA9.0+cuDNN7.0 环境简明搭建指南

    最近在研究风格化得内容,发现搭建环境实在是很头疼的事情,虽然网上已经有各路大神总结整理好了很多搭建指南,各种问题的解决方案都已经罗列出来供大家参考.然后参考终究是参考,真正自己上手,发现仍旧是各种坑, ...

  8. mysql-9-limit

    #进阶9:分页查询 /* 当要显示的数据,一页显示不全,需要分页提交sql请求 SELECT FROM JOIN ON WHERE GROUP BY HAVING ORDER BY LIMIT off ...

  9. Anaconda安装Pytorch(通过本地安装包)

    前提:你已经事先安装好了Anaconda 在线安装pytorch总是出现这样那样的问题,所以我选择先去清华镜像下载好与python版本对应的pytorch和torchvision文件,然后本地安装 清 ...

  10. 【Linux】一些文件限制配置

    linux资源限制配置文件是/etc/security/limits.conf:限制用户进程的数量对于linux系统的稳定性非常重要. limits.conf文件限制着用户可以使用的最大文件数,最大线 ...