ThinkPHP 实现队列

官方文档: top-think/think-queue

应用场景: 

   队列适用与多个用户同时执行一个操作,或适用与单个用户多次执行同一个操作

  1. 消息队列,发送邮件、短信
  2. 用户订单提交

缺点:

   一旦需处理数据加入到任务内就不能删除,如果删除可以使用redis 

 

队列文件:

Tp6  config/queue.php 配置文件 ,启动reids 服务

/**
 * 消息队列配置
 * 内置驱动:redis、database、topthink、sync
*/
return [
    //sync驱动表示取消消息队列还原为同步执行
    //'connector' => 'sync',

    //Redis驱动
    'connector' => 'redis',
    "expire"=>60,//任务过期时间默认为秒,禁用为null
    "default"=>"default",//默认队列名称
    "host"=>Env::get("redis.host", "127.0.0.1"),//Redis主机IP地址
    "port"=>Env::get("redis.port", 6379),//Redis端口
    "password"=>Env::get("redis.password", "123456"),//Redis密码
    "select"=>5,//Redis数据库索引
    "timeout"=>0,//Redis连接超时时间
    "persistent"=>false,//是否长连接

    //Database驱动
    //"connector"=>"Database",//数据库驱动
    //"expire"=>60,//任务过期时间,单位为秒,禁用为null
    //"default"=>"default",//默认队列名称
    //"table"=>"jobs",//存储消息的表明,不带前缀
    //"dsn"=>[],

    //Topthink驱动 ThinkPHP内部的队列通知服务平台
    //"connector"=>"Topthink",
    //"token"=>"",
    //"project_id"=>"",
    //"protocol"=>"https",
    //"host"=>"qns.topthink.com",
    //"port"=>443,
    //"api_version"=>1,
    //"max_retries"=>3,
    //"default"=>"default"
];

app/queue/controller/Execjob 创建单个任务

namespace app\queue\controller;
use think\queue\Job;
use think\Exception;

class Execjob
{
    public function fire(Job $job, $data)
    {    
        // 这里执行具体的任务,如果方法不存在,或参数出错,致命错误时
        try{
          //调用函数方法,如果使用ThinkPHP app\模块\控制器\类名@方法名,使用action方法
          $result=call_user_func_array($data['action'],$data['param']); 
        }catch (Exception $e){
            // 错误处理
        }

        if($result)
        {
           //如果任务执行成功后 记得删除任务,不然这个任务会重复执行,直到达到最大重试次数后失败后,执行failed方法
            $job->delete();

        }else{
            $delay=config('config.fail_repeat_delay');
            $job->release($delay); //如果执行失败,$delay为延迟时间重新执行
        }

        $fail_exec_number=config('queue.fail_exec_number');
        if ($job->attempts() > $fail_exec_number) {
            //通过这个方法可以检查这个任务已经重试了几次了
            $job->delete(); 
        }
    }

    public function failed(Execjob $job)
    {
        // ...任务达到最大重试次数后,失败了,可以添加一些其他的操作,会自动调用,如同 fire()方法
        $job->delete();
    }
}    

app/queue/controll/jobqueue.php  发布单个任务(其他页面调用当前方法)

namespace app\queue\controller;
use think\Queue;

class Jobqueue
{
    /**
     * queueTest
     * @param $queue 调用任务类文件名
     * @param $data array 执行方法的参数数据 action 具体任务方法名,param 方法名参数
     * @param $delay 消息队列延迟时间,单位秒
     */
    public function queueTest(string $queue,array $data=[],int $delay){

        //创建任务: 项目命名空间\控制器@方法
         $job = "app\queue\controller\Execjob";

        // 如果立即发送
        if(!$delay){
            /*
            * $job   类的命名空间\类名 app\queue   
            *        其他的需要些完整的类名,需要写完整的类名  app\queue\controller\job
            *        如果一个任务类里有多个小任务的话,类的命名空间\类名@方法,app\queue\controller\Execjob2@task1,app\queue\controller\Execjob2@task2
            * $data 是你要传到任务里的参数 
            * $queue 队列名,指定这个任务是在哪个队列上执行,同下面监控队列的时候指定的队列名,可不填
            */    
            $result = Queue::push($job, $data, $queue);
        }else{
            //如果延时发送
            $result = Queue::later($delay, $job, $data, $queue);
        }
        //dump($result); // database 驱动时,返回值为 1|false  ;   redis 驱动时,返回值为 随机字符串|false
        // 当前页面为同步页面
    }
}

 

监听队列

写完之后再控制器切换到当前目录下执行,任务的监听、执行

//  --queue 队列名称,不指定监听所有队列
php think queue:listen --queue send_mail

 

测试访问页面

http://tp.com/pub/test/index,任务的调用

<?php
namespace app\pub\controller;

use app\queue\controller\Jobqueue;
use think\Controller;

class Test extends Controller
{
    public function index(){
      $job_queue=new Jobqueue();
      $job_queue->queueTest('send_mail',['develophp@foxmail.com','sa','测试']); // send_mail()  定义在common.php 文件中
    }
}

队列执行完成后,处于等待下次调用

队列流程:创建 ->发布 ->监听 -> 调用/推送 ->删除

 

调用多个任务

app/queue/controller/Execjob2 创建多个任务

namespace app\queue\controller;

use think\queue\Job;
class Execjob2{
    
    public function task1(Job $job, $data){
            // 具体任务 
    }
    
    public function task2(Job $job, $data){  
          // 具体任务
    }
    
    // 还有个可选的任务失败执行的方法 failed 传入的参数为$data(发布任务时自定义的数据),会自动调用
    public function failed($data){   
         // 任务执行失败调用当前方法
      
    }
}

app/queue/controll/jobqueue2.php  发布任务(直接调用)

namespace app\queue\controller;

use think\Queue;

class Jobqueue2
{
    
    public function queueTest(){
        //....这里执行具体的任务 
        /*
        * $job   类的命名空间\类名 app\queue   
        *        其他的需要些完整的类名,需要写完整的类名  app\queue\controller\job
        *        如果一个任务类里有多个小任务的话,类的命名空间\类名@方法,app\queue\controller\Execjob2@task1,app\queue\controller\Execjob2@task2
        */   
        $job='app\queue\controller\Execjob2@task2';
        $data=1;  //是你要传到任务里的参数 
        $delay=config('config.fail_repeat_delay'); // 延迟时间,单位秒
     $queue='work';  // 队列名,指定这个任务是在哪个队列上执行,同下面监控队列的时候指定的队列名,可不填
        // 如果立即发送
        if(!$delay){ 
            $result = Queue::push($job, $data, $queue);
        }else{
            //如果延时发送
            $result = Queue::later($delay, $job, $data, $queue);
        }
        //dump($result); // database 驱动时,返回值为 1|false  ;   redis 驱动时,返回值为 随机字符串|false
        // 当前页面为同步页面
    }
}

 

监听队列

写完之后再控制器切换到当前目录下执行,任务的监听、执行

//  --queue 队列名称,不指定监听所有队列
php think queue:listen --queue work

// 或者
php think queue:listen
php think queue:work

 

测试访问页面

http://tp.com/queue/jobqueue2/queueTest  任务的推送

队列执行完成后,处于等待下次调用

队列流程:创建 ->发布 ->监听 ->调用/推送 ->删除

 

相关文章:tp5.1_队列queue学习

 thinkphp-queue 笔记

      think-queue使用教程-用户注册场景异步发送邮件

  think-queue

posted @ 2020-06-12 16:23  柔和的天空  阅读(3505)  评论(0编辑  收藏  举报