YII2---队列的初步整理(yii2-queue+beanstalk+pheanstalk)

      虽然接触过几门语言,但是在大佬们谈论队列的时候还总是像是一座大山,经过一段时间的整理,以下我来谈谈我对队列的看法(路过大神扶正请温柔)。

==  关于队列  ==


1.队列就像是一个容器,把来不及操作的东西井然有序的放入。

2.通俗的讲,可以把队列看做一个城市的马路。有很多马路,各有各的秩序和走向,先驶入的先走出马路,马路与马路车辆不会相互影响。队列里的内容是有一定规格的,就想机动车和非机动车一样,相同规格的在相同的路上行进。

3.队列就像线性表一样,两头都可以操作,但是表头只出表尾只进,表中的内容只是进行存储。

这样看难点就在于,表存在什么地方,在表中的数据什么时候取出,操作失败之后要怎么办等。于是这个时候就需要驱动,扩展,插件等来辅助了。

==  关于 yii2-queue YII原生福利 ==

1,安装

利用composer快速安装 .    php composer.phar require --prefer-dist yiisoft/yii2-queue

2,配置

在config中添加配置‘queue’的信息。由于这个yii原生的队列可以支持多种驱动,所以在配置前还是要先选好驱动。

参考:https://github.com/yiisoft/yii2-queue/tree/master/docs/guide-zh-CN

测试实例:示例是console的config/main.php中配置方式

1.File

这里的第一个queue是file驱动型。是把放入队列的数据加密存储成一个个文件(可能会被规则命名为job1.data的形式)。这里要注意path。由于YII的每个项目中存在多个APP,配置文件可以相互独立,队列在项目前端APP中进行添加,所以需要在该APP配置队相同的内容,但是要注意一点,这里的path需要指到相同的位置。

2.Redis

第三个是redis驱动,这里要注意的是redis是要另外配置,可以在common的APP中config/main-local.php。配置方式类似下图:

另外DB形式和redis类似,配置好db部分和queue部分(redis也可以看做是非关系型数据库的一种,这里对数据存储处理几乎一致)

3.Beanstalk

作为主流驱动兔子比较受欢迎,但是兔子系列的基本都是比较大型的,一般小项目PHP选用beanstalk也比较多。(而且就个人原因手上的旧项目选用的也是这个,在使用和表述上有据可考也是极好)所以我原则beanstalk进行深入表述

beanstalk是可以在其他框架下仍然好用的软件,这里我要从三种不同的方式操作。首先就是今天的主题,利用YII2-queue,其二是用udokmeci\yii2beanstalk,第三就是pheanstalk。这三种都是对beanstalk进行操作,三者可以交错使用。

  ------   利用yii2soft/yii2-queue   ------  

其中的存储类型是特殊的,我们需要先新建一个类。

<?php
/**
 * Created by PhpStorm.
 * User: loong
 * Date: 2018/1/9
 * Time: 09:30
 */

namespace forTool\modules\v1\models\common;

use Yii;
//use yii\queue\JobInterface;
use common\base\controllers\ExcelDeal;
use yii\queue\RetryableJobInterface;

class BaseJob implements RetryableJobInterface
{


    public $url;//存储的json格式键名,为方便获取,会定义成属性
    public $file;


    public function __construct($array)
    {
        $this->url = $array['url'];

        $this->file = $array['file'];

        return $this;
    }

//这个函数是必须要有的因为接口的实现,这里的函数是在队列入队执行的
    public function execute($queue)
    {
        echo '我正在执行队列。。。';
        var_dump($this);
        file_put_contents($this->file, file_get_contents($this->url));
    }
//这个是对队列任务的延迟设置
    public function getTtr()
    {
        echo 'ttr';
        return 15 * 60;
    }
//设置任务的延迟重复
    public function canRetry($attempt, $error)
    {
        echo 'can try';
        return ($attempt < 5) && ($error );
    }


}

我的这个类叫BaseJob,所以之后的队列如果利用yii2-queue进行封装入队时就需要用这里类作为存储。

例如在需要入队的时候:

 $id_11 = Yii::$app->queue->push(new BaseJob([
            'url' => 'http://img3.imgtn.bdimg.com/it/u=1243131531,3821032402&fm=27&gp=0.jpg',
            'file' => '../runtime/tmp/image.jpg',
        ]));

当然数据结构是根据个人而定,这里是可以完成图片下载的逻辑,入队的是图片下载地址和将下载存储的地址。队列中数据的处理则写在execute()中

那么问题出来了,数据在什么时候才能出队?什么时候才能执行?和其他驱动类似,我们可以用:php yii queue/listen

来监听队列,如果非延迟任务入队将直接执行相应的exectue。延迟任务则在相应时间之后执行。另外还可以使用:php yii queue/info 来检查队列状态。php yii remove [id] 来移除指定的ID任务。等等命令,这些都是通过在console配置直接执行的。队列情况实例如下:

==  关于 beanstalk  ==

在正式开始之前就涉及到一个关于提供服务问题,在上一个模块的最后提到了关于beanstalk.这里出现一个问题,我的实例代码是按照本机是提供服务配置的,显然这里提供服务的是本机,如果需要其他的机子就换掉IP和端口就好,但是要吧本机作为主机嘞~
1.配置beanstalk服务主机。

(1)安装(基于MAC)

brew install beanstalk

(2)确认安装成功

执行相关帮助或查询版本的命令;例如:beanstalk -h

(3)开启服务

beanstalk -l 地址 -p 端口号

参考资料:
http://blog.csdn.net/ahjxhy2010/article/details/53196450

https://segmentfault.com/a/1190000002784775

http://www.51siyuan.cn/91.html

https://getyii.com/topic/531

2.基于beanstalk的入队操作

参考:

http://blog.csdn.net/taotaobaobei/article/details/78570963

http://blog.csdn.net/taotaobaobei/article/details/78571063

很多网站上都没又说这两个的区别,方法也是混着用的,(或许在其他框架是一样的)但是YII在两种的入队方式不大相同。

(1)udokmeci\yii2beanstalk

      (a)安装  :composer require udokmeci\yii2beanstalk

      (b)使用:
(i)配置

        'beanstalk'=>[
            'class' => 'udokmeci\yii2beanstalk\Beanstalk',
            'host'=> "127.0.0.1", // default host
            'port'=>11300, //default port
            'connectTimeout'=> 1,
            'sleep' => false, // or int for usleep after every job
        ],

(ii)入队

  $bean = Yii::$app->beanstalk;

  $bean->putInTube('tubequeue',['unique_id' => 11, 'source' => 2, 'method'=> 'get']);

这里入队的时候有较大区别,但在执行的时候都是一个文件

(2)pda/pheanstalk(https://github.com/pda/pheanstalk/)

      (a)安装  :composer require pda/pheanstalk

      (b)执行

(i)配置:

看起来主流的都是实例化对象进行调用,并没配置,不过可以封装一个类自动填写实例化内容

(ii)入队。这里要注意的是,入队的内容要转成JSON格式

这个是主流PHP中对beanstalk的操作依赖,可以有较灵活的操作,获取状态,管道名称个数,获取某个管道的状态信息等

(3)yii-queue

         安装和入队和前面讲的一样。

3.关于beanstalk的执行

利用上面提到的(1),(2)两种。数据处理的类别是要集成BeanstalkController的。例如:
 

<?php
/**
 * Created by PhpStorm.
 * User: loong
 * Date: 2018/1/6
 * Time: 11:27
 */

namespace console\controllers;

use yii;
use udokmeci\yii2beanstalk\BeanstalkController;
class JobController  extends BeanstalkController

{

    public $url;
    public $file;


    // Those are the default values you can override

    const DELAY_PRIORITY = "1000"; //Default priority
    const DELAY_TIME = 5; //Default delay time

    // Used for Decaying. When DELAY_MAX reached job is deleted or delayed with
    const DELAY_MAX = 3;

    public function listenTubes(){
//        return ["tube"];
        return ["tubequeue","tubePhean"];

    }

    public function actionTubePhean($job){
        try {

            $sentData = $job->getData();
            //相应操作
        }
        catch (\Exception $e) {
            //If there is anything to do.
            fwrite(STDERR, Console::ansiFormat($e."\n", [Console::FG_RED]));
            // you can also bury jobs to examine later
            return self::BURY;
        }
    }


    public function actionTubequeue($job){
        try {


            $sentData = $job->getData();
            //相应操作
        }
        catch (\Exception $e) {
            //If there is anything to do.
            fwrite(STDERR, Console::ansiFormat($e."\n", [Console::FG_RED]));
            // you can also bury jobs to examine later
            return self::BURY;
        }
    }

    /**
     *
     * @param Pheanstalk\Job $job
     * @return string  self::BURY
     *                 self::RELEASE
     *                 self::DELAY
     *                 self::DELETE
     *                 self::NO_ACTION
     *                 self::DECAY
     *
     */
    public function actionTube($job){
//        $sentData = $job->getData();
        try {
            $sentData = $job->getData();

            //相应操作

            // something useful here

            

            // if you return anything else job is burried.
        } catch (\Exception $e) {
            //If there is anything to do.
            fwrite(STDERR, Console::ansiFormat($e."\n", [Console::FG_RED]));
            // you can also bury jobs to examine later
            return self::BURY;
        }
    }

}

上面是一个简单的示例,没有对取到的数据做任何操作,只是去取出各种存入的数据。只看其中必要问题。

要点一:

对于: listenTubes()是表述监听的tube的名字。类似于php yii queue/listen的作用,会主动开启监听。

要监听多个tbue时。就要写成数组的形式。

要点二:

对于不同tbue的操作是利用不同函数区分,函数要用tube的名字命名。要注意对不同处理结果的处理

另外再补充几个借鉴资料的文章:

http://www.360doc.com/content/16/0712/11/9200790_574926294.shtml

https://www.cnblogs.com/yingmo/p/6148380.html

http://www.yiichina.com/extension/1084

http://www.mamicode.com/info-detail-1485697.html

猜你喜欢

转载自my.oschina.net/jlong/blog/1631161
今日推荐