加入收藏 | 设为首页 | 会员中心 | 我要投稿 衡阳站长网 (https://www.0734zz.cn/)- 数据集成、设备管理、备份、数据加密、智能搜索!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

PHP轻松实现延时操作

发布时间:2022-07-20 04:19:18 所属栏目:PHP教程 来源:互联网
导读:场景:在业务中有时会碰到延迟操作,如下单后半小时未支付则取消订单、下单后十五分钟未支付则发短信提醒等等。那这样的需求如何去实现呢。 实现方式 第一个简单的方式就是用一个后台进程死循环去查订单,根据下单时间去做不同的操作 第二种就是使用消息队列
  场景:在业务中有时会碰到延迟操作,如下单后半小时未支付则取消订单、下单后十五分钟未支付则发短信提醒等等。那这样的需求如何去实现呢。
 
  实现方式
 
  第一个简单的方式就是用一个后台进程死循环去查订单,根据下单时间去做不同的操作
 
  第二种就是使用消息队列的定时消息,下单之后发送定时消息,不同的定时队列去处理不同的逻辑
 
  第三种可以使用框架提供的一些既有功能去做
 
  实现代码
 
  我们以订单创建15分钟后未支付,给用户发送邮件为场景进行学习
 
  准备工作:
 
  简单的订单表:order
 
  各种需要的composer包
 
  rabbitMq本地服务
 
  开通阿里云RocketMq服务
 
  第一种
 
  比如使用阿里云的MQ服务,目前rocketMq与rabbitMq版本支持延迟消息,但是rabbit的延时消息收费太高了
 
  这里先使用rocketMq的延迟消息去实现
 
  需要开通阿里云的服务
 
  消费逻辑 同样是在消费者中处理

  启动生产一条消息
 
  gaoz@nobodyMBP delay_mq_demo % php rocket_mq_handler_producer.php
 
  Send mq message success. msgId is:76CF2135696C3D4EAC698A9FA1E1879D, bodyMD5
 
  is:63448B50AA7B8AF47B07AA7CE807E3D3
 
  gaoz@nobodyMBP delay_mq_demo %
 
  启动消费者慢慢等待
 
  gaoz@nobodyMBP delay_mq_demo % php rocket_mq_handler_consumer.php
 
  No message, contine long polling!RequestId:5EF752583441411C74869BA9
 
  No message, contine long polling!RequestId:5EF7525B3441411C74869FE2
 
  No message, contine long polling!RequestId:5EF7525E3441411C7486A42C
 
  No message, contine long polling!RequestId:5EF752613441411C7486A7D9
 
  consume finish, messages:send email to 95 success ...2020-06-27 12:08:05:update-success-orderId-8-userId-95
 
  Array(
 
  
      [0] => 76CF2135696C3D4EAC698A9FA1E1879D-MCAxNTkzMjY2NzkxNDM5IDMwMDAwMCAzIDAgYmpzaGFyZTUtMDggNSAw)
  ack
 
  这种方式有现有的服务可以使用,减少开发时间

       第二种
 
  代码逻辑很简单就直接死循环就行了
 
  启动这个脚本进程,可以用supervisor配置
 
  部分代码
 
  //创建订单的逻辑/**
  
   * 随机创建订单
  
   */$order = [
  PHP轻松实现延时操作
      'order_number' => mt_rand(100,10000).date("YmdHis"),
  
      'user_id' => mt_rand(1, 100),
  
      'order_amount' => mt_rand(100, 1000),];
  
      /**@var $manager IlluminateDatabaseCapsuleManager **/
  
      $conn = $manager;$insertResult = $conn::table("order")
  
      ->insert($order);print_r($insertResult);
  延迟处理逻辑
 
  while(true) {
  
      // 未支付订单列表
  
      $orderList = $conn::table("order")
  
          ->where("created_time",  '<=', date("Y-m-d H:i:s", strtotime("-15 minutes")))
  
          ->where('sended_need_pay_notify', '=', 2)
  
          ->where('status', '=', 1)
  
          ->select(['user_id', 'id'])
  
          ->orderBy("id", 'asc')
  
          ->get();
  
      $orderList = json_decode(json_encode($orderList), true);
  
      foreach ($orderList as $orderInfo) {
  
          sendEmail($orderInfo['user_id']);
  
          $conn::table('order')
  
              ->where('id', '=', $orderInfo['id'])
  
              ->update(['sended_need_pay_notify' => 1]);
  
          logs("update-success-orderId-". $orderInfo['id']."-userId-".$orderInfo['user_id']);
  
      }
  
      sleep(10);}
  执行处理脚本
  gaoz@nobodyMBP delay_mq_demo % php first_while_handler.php
 
  send email to 73 success ...
 
  2020-06-24 11:37:36:update-success-orderId-3-userId-73
 
  这种方式吧实现简单,但是不优雅,同时大批量订单产生也会遇到问题。

  第三种 使用rabbitMq去实现
 
  查阅文档没有找到rabbitMq支持延迟队列的原生功能,但是可以通过消息的ttl+死信队列实现
 
  私信队列就是用来存放没有被消费或者消费失败等消息的队列
 
  当设置消息的有效期内没有被消费消息就会被转发到死信队列
 
  通过设置消息的有效期实现延时功能
 
  // 生产者$exchange = 'order15min_notify_exchange';
  
  $queue = 'order15minx_notify_queue';$dlxExchange = "dlx_order15min_exchange";
  
  $dlxQueue = "dlx_order15min_queue";
  
  $connection = new AMQPStreamConnection(getenv('RABBIT_HOST'), getenv('RABBIT_PORT'), getenv("RABBIT_USER"), getenv("RABBIT_PASS"), getenv("RABBIT_VHOST"));
 
  第四种
 
  使用laravel自带的Queue去实现
 
  这里没有整理详细代码,后面更新出来。

(编辑:衡阳站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读