• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
孙龙 程序员
少时总觉为人易,华年方知立业难
博客园    首页    新随笔    联系   管理    订阅  订阅
rabbitmq延时队列

场景一:物联网系统经常会遇到向终端下发命令,如果命令一段时间没有应答,就需要设置成超时。

场景二:订单下单之后30分钟后,如果用户没有付钱,则系统自动取消订单。

最近的一个项目遇到了这种情况,如果运单30分钟还没有被接单,则状态自动变为已取消。实现延迟消息原理如下,借用一张图:

 

实现方案

  1. 定时任务轮询数据库,看是否有产生新任务,如果产生则消费任务

  2. pcntl_alarm为进程设置一个闹钟信号

  3. swoole的异步高精度定时器:swoole_time_tick(类似javascript的setInterval)和swoole_time_after(相当于javascript的setTimeout)

  4. rabbitmq延迟任务

以上四种方案,如果生产环境有使用到swoole建议使用第三种方案。此篇文章重点讲述第四种方案实现

 

 

 

 1 <?php
 2 require_once __DIR__ . '/../vendor/autoload.php';
 3 use PhpAmqpLib\Connection\AMQPStreamConnection;
 4 use PhpAmqpLib\Message\AMQPMessage;
 5 
 6 
 7 $queue = "test_ack_queue";
 8 $exchange = "test_ack_queue";
 9 //获取连接
10 $connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
11 //从连接中创建通道
12 $channel = $connection->channel();
13 
14 $channel->exchange_declare('delay_exchange', 'direct',false,true,false);
15 $channel->exchange_declare('cache_exchange', 'direct',false,true,false);
16 
17 $tale = new \PhpAmqpLib\Wire\AMQPTable();
18 $tale->set('x-dead-letter-exchange', 'delay_exchange');
19 $tale->set('x-dead-letter-routing-key','delay_exchange');
20 //$tale->set('x-message-ttl',10000);
21 
22 $channel->queue_declare('cache_queue',false,true,false,false,false,$tale);
23 $channel->queue_bind('cache_queue', 'cache_exchange','cache_exchange');
24 
25 $channel->queue_declare('delay_queue',false,true,false,false,false);
26 $channel->queue_bind('delay_queue', 'delay_exchange','delay_exchange');
27 
28 
29 $msg = new AMQPMessage('Hello World',array(
30     'expiration' => 10000,
31     'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT
32 
33 ));
34 
35 $channel->basic_publish($msg,'cache_exchange','cache_exchange');
36 echo date('Y-m-d H:i:s')." [x] Sent 'Hello World!' ".PHP_EOL;
37 
38 
39 
40 
41 //while ($wait) {
42 //    $channel->wait();
43 //}
44 
45 $channel->close();
46 $connection->close();
task

 

 

 1 <?php
 2 require_once __DIR__ . '/../vendor/autoload.php';
 3 use PhpAmqpLib\Connection\AMQPStreamConnection;
 4 use PhpAmqpLib\Message\AMQPMessage;
 5 
 6 
 7 //获取连接
 8 $connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
 9 //从连接中创建通道
10 $channel = $connection->channel();
11 
12 
13 //$channel->queue_declare($queue, false, true, false, false);
14 //$channel->exchange_declare($exchange, 'topic', false, true, false);
15 //$channel->queue_bind($queue, $exchange);
16 
17 
18 
19 $channel->exchange_declare('delay_exchange', 'direct',false,false,false);
20 $channel->queue_declare('delay_queue',false,true,false,false,false);
21 $channel->queue_bind('delay_queue', 'delay_exchange','delay_exchange');
22 
23 
24 
25 function process_message(AMQPMessage $message)
26 {
27     $headers = $message->get('application_headers');
28     $nativeData = $headers->getNativeData();
29 //    var_dump($nativeData['x-delay']);
30     echo date('Y-m-d H:i:s')." [x] Received",$message->body,PHP_EOL;
31     $message->delivery_info['channel']->basic_ack($message->delivery_info['delivery_tag']);
32 
33 }
34 
35 
36 $channel->basic_qos(null, 1, null);
37 $channel->basic_consume('delay_queue', '', false, false, false, false, 'process_message');
38 
39 function shutdown($channel, $connection)
40 {
41     $channel->close();
42     $connection->close();
43 }
44 register_shutdown_function('shutdown', $channel, $connection);
45 
46 while (count($channel->callbacks)) {
47     $channel->wait();
48 }
work

 

 

 

 

 

 

本文来自博客园,作者:孙龙-程序员,转载请注明原文链接:https://www.cnblogs.com/sunlong88/articles/10087901.html

posted on 2018-12-08 15:44  孙龙-程序员  阅读(311)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3