tp队列thinkphp-queue使用笔记

thinkphp-queue 是thinkphp 官方提供的一个消息队列服务,我们可用它来做一些需要用到队列的功能,如抢购等,也可用它来实现定时任务功能

1、安装

tp5支持的thinkphp-queue版本为2.0.*,3.0以上的版本需要tp6以上的环境

composer 安装代码:composer require topthink/think-queue=2.0.*

2、搭建消息队列的储存环境

  • 使用 Redis [推荐]

    安装并启动 Redis 服务
    
    • 使用数据库 [不推荐]

      CREATE TABLE `prefix_jobs` (
        `id` int(11) NOT NULL AUTO_INCREMENT, 
        `queue` varchar(255) NOT NULL,  //队列名称
        `payload` longtext NOT NULL,   //数据和指定的消费类信息在这里面
        `attempts` tinyint(3) unsigned NOT NULL,  //执行的次数
        `reserved` tinyint(3) unsigned NOT NULL,  //0未执行 1执行中
        `reserved_at` int(10) unsigned DEFAULT NULL,  //开始执行的时间戳
        `available_at` int(10) unsigned NOT NULL,  //最早可执行的时间
        `created_at` int(10) unsigned NOT NULL,    //创建时间
        PRIMARY KEY (`id`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

3、消息队列配置

在 站点根目录/config/queue.php中设置配置信息

 return [
       'connector'  => 'Redis',		// Redis 驱动
       'expire'     => 60,		// 任务的过期时间,默认为60秒; 若要禁用,则设置为 null 
       'default'    => 'default',		// 默认的队列名称
       'host'       => '127.0.0.1',	// redis 主机ip
       'port'       => 6379,		// redis 端口
       'password'   => '',		// redis 密码
       'select'     => 0,		// 使用哪一个 db,默认为 db0
       'timeout'    => 0,		// redis连接的超时时间
       'persistent' => false,		// 是否是长连接
     
   //    'connector' => 'Database',   // 数据库驱动
   //    'expire'    => 60,           // 任务的过期时间,默认为60秒; 若要禁用,则设置为 null
   //    'default'   => 'default',    // 默认的队列名称
   //    'table'     => 'jobs',       // 存储消息的表名,不带前缀
   //    'dsn'       => [],

   //    'connector'   => 'Topthink',	// ThinkPHP内部的队列通知服务平台 ,本文不作介绍
   //    'token'       => '',
   //    'project_id'  => '',
   //    'protocol'    => 'https',
   //    'host'        => 'qns.topthink.com',
   //    'port'        => 443,
   //    'api_version' => 1,
   //    'max_retries' => 3,
   //    'default'     => 'default',

   //    'connector'   => 'Sync',		// Sync 驱动,该驱动的实际作用是取消消息队列,还原为同步执行
   ];

4、消息队列的创建和推送

  在app\index\controller\index中创建方法addHelloJob方法

 time(), 'bizId' => uniqid() , 'a' => 1 ] ;
      
      // 4.将该任务推送到消息队列,等待对应的消费者去执行
      $isPushed = Queue::push( $jobHandlerClassName , $jobData , $jobQueueName );	
      
      // database 驱动时,返回值为 1|false  ;   redis 驱动时,返回值为 随机字符串|false
      if( $isPushed !== false ){  
          echo date('Y-m-d H:i:s') . " a new Hello Job is Pushed to the MQ"."
"; }else{ echo 'Oops, something went wrong.'; } } }

5、消息队列的消费和删除

编写 Hello 消费者类,用于处理 helloJobQueue 队列中的任务

新增 \application\index\job\Hello.php 消费者类,并编写其 fire() 方法

 checkDatabaseToSeeIfJobNeedToBeDone($data);
          if(!$isJobStillNeedToBeDone){
              $job->delete();
              return;
          }
        
          $isJobDone = $this->doHelloJob($data);
        
          if ($isJobDone) {
              // 如果任务执行成功, 记得删除任务
              $job->delete();
              print("Hello Job has been done and deleted"."\n");
          }else{
              if ($job->attempts() > 3) {
                  //通过这个方法可以检查这个任务已经重试了几次了
                  print("Hello Job has been retried more than 3 times!"."\n");
                  
  				        $job->delete();
                  
                  // 也可以重新发布这个任务
                  //print("Hello Job will be availabe again after 2s."."\n");
                  //$job->release(2); //$delay为延迟时间,表示该任务延迟2秒后再执行
              }
          }
      }
      
      /**
       * 有些消息在到达消费者时,可能已经不再需要执行了
       * @param array|mixed    $data     发布任务时自定义的数据
       * @return boolean                 任务执行的结果
       */
      private function checkDatabaseToSeeIfJobNeedToBeDone($data){
          return true;
      }

      /**
       * 根据消息中的数据进行实际的业务处理...
       */
      private function doHelloJob($data) 
      {
          print("Hello Job Started. job Data is: ".var_export($data,true)." \n");
          print("Hello Job is Fired at " . date('Y-m-d H:i:s') ." \n");
          print("Hello Job is Done!"." \n");
          
          return true;
      }

  }

6、发布任务

  在浏览器访问app\index\controller\index中的addHelloJob方法,就会创建一条消息队列信息到队列中

7、消费消息队列

切换到终端项目根目录下执行:php think queue:work --queue helloJobQueue

就会消费掉队列中的一条消息,该命令消费一条消息后就会退出执行,如果想消费者类一直跑着,一有消息发布到队列中就消费。可使用:php think queue:work --queue helloJobQueue --daemon 或者 php think queue:listen --queue helloJobQueue

8、 消息的延迟执行与定时执行

延迟执行,相对于即时执行,是用来限制某个任务的最早可执行时刻。在到达该时刻之前,该任务会被跳过。

可以利用该功能实现定时任务

使用方式:

  • 在生产者业务代码中:
// 即时执行
$isPushed = Queue::push($jobHandlerClassName, $jobDataArr, $jobQueueName);

// 延迟 2 秒执行
$isPushed = Queue::later( 2, $jobHandlerClassName, $jobDataArr, $jobQueueName);

// 延迟到 2017-02-18 01:01:01 时刻执行
$time2wait = strtotime('2017-02-18 01:01:01') - strtotime('now');	
$isPushed = Queue::later($time2wait,$jobHandlerClassName, $jobDataArr, $jobQueueName);
  • 在消费者类中:
// 重发,即时执行
$job->release();

// 重发,延迟 2 秒执行
$job->release(2);

// 延迟到 2017-02-18 01:01:01 时刻执行
$time2wait = strtotime('2017-02-18 01:01:01') - strtotime('now');
$job->release($time2wait);

8、实现计划任务

1、任务如订单超时回收,可在每次下单时发布一条消息到队列中,设置好延迟执行时间,在消费者类中查到相应的订单id并做相应的操作

2、第二种方法,发布一条消息,延迟5分钟执行,在消费者类中将所有超时未付款的订单作废,在重发此消息任务

 

更详细细节参考:https://github.com/coolseven/notes/blob/master/thinkphp-queue/README.md

 

 

 

 

你可能感兴趣的:(php,thinkphp,thinkphp-queue)