RabbitMQ使用延迟队列实现一次性定时任务(php版)

本文建立在读者对RabbitMQ的基础了解上

本文延迟队列实现参照 https://blog.csdn.net/u012119576/article/details/74677835

对相关概念的理解参照 https://blog.csdn.net/samxx8/article/details/47417133

作为phper在实现诸如“课程开启后十分钟推送消息”,"订单生成后多少分钟自动取消"这类问题上会有一些问题,目前我能想到的三种解决方案有:

               1. swoole有settimeout

               2.exec设置linux系统一次性定时器  at命令(atd包) ,windows服务器上好像直接可以设置,但是最低间隔是一分钟还是30s,具体忘了。。。

               3.crontab设置定时器检查(不建议。。。)

最近在弄RabbitMQ时,发现可以使用延迟队列实现这类需求。具体原理是新建两条队列绑定对应的交换机,其中一条设置消息延迟执行,在到期后使用交换机丢到与客户端连接的队列中,发送给客户端,具体参见代码。

send.php

<?php

require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Wire\AMQPTable;

$connection = new AMQPStreamConnection('127.0.0.1', 5672, 'guest', 'guest');
$channel = $connection->channel();
//给cache发送  使其过期然后定向到另一个
//声明两个队列
$channel->exchange_declare('delay_exchange', 'direct',false,false,false);
$channel->exchange_declare('cache_exchange', 'direct',false,false,false);

$tale = new AMQPTable();
$tale->set('x-dead-letter-exchange', 'delay_exchange');//****很关键  表示过期后由哪个exchange处理
$tale->set('x-dead-letter-routing-key','delay_exchange');//****很关键  表示过期后由哪个exchange处理
//$tale->set('x-message-ttl',15000);  //存活时长   下面的过期时间不能超过

$channel->queue_declare('cache_queue',false,true,false,false,false,$tale);
$channel->queue_bind('cache_queue', 'cache_exchange','cache_exchange');

$channel->queue_declare('delay_queue',false,true,false,false,false);
$channel->queue_bind('delay_queue', 'delay_exchange','delay_exchange');


$msg = new AMQPMessage('Hello World'.'3000',array(
    'expiration' => intval(18000),
    'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT

));

$channel->basic_publish($msg,'cache_exchange','cache_exchange');
echo date('Y-m-d H:i:s')." [x] Sent 'Hello World!' ".PHP_EOL;

$channel->close();
$connection->close();

reciever.php

<?php

require_once __DIR__ . '/../vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;

$connection = new AMQPStreamConnection('127.0.0.1', 5672, 'guest', 'guest');
$channel = $connection->channel();

$channel->exchange_declare('delay_exchange', 'direct',false,false,false);
$channel->exchange_declare('cache_exchange', 'direct',false,false,false);


$channel->queue_declare('delay_queue',false,true,false,false,false);
$channel->queue_bind('delay_queue', 'delay_exchange','delay_exchange');

echo ' [*] Waiting for message. To exit press CTRL+C '.PHP_EOL;

$callback = function ($msg){
    echo date('Y-m-d H:i:s')." [x] Received",$msg->body,PHP_EOL;

    $msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);

};

//只有consumer已经处理并确认了上一条message时queue才分派新的message给它
$channel->basic_qos(null, 1, null);
$channel->basic_consume('delay_queue','',false,false,false,false,$callback);


while (count($channel->callbacks)) {
    $channel->wait();
}
$channel->close();
$connection->close();

猜你喜欢

转载自blog.csdn.net/wufantastic/article/details/86230406