abei1982 2018-02-06 09:46:31 3013次浏览 1条回复 1 0 0

之前群里很多会员说如何用yii2实现队列功能,这个系列我们就来说说yii2官方的队列扩展yii2-queue,细节很多,第一篇通过一个例子带你入门。

先说需求吧~

我想做这样一个功能:每次有新视频发布的时候,给订阅过此视频所在教程的会员发送一条模板消息,但是我如果在发布课程的时候就一次性发送模板消息有可能导致速度问题和被封的危险。

所以我想将接收者们在时间上分开,比如100个人,每5-10秒发送一个,我用yii2-queue来实现它

yii2-queue是yii2官方去年推出的一个扩展,支持延迟推送并且队列可以存储到多种媒介中,比如文件、数据库等等。

在队列中有几个概念要先说下

任务(task) 就是我们具体要做的事情,在本次就是发送微信模板消息这样一件事情,yii2-queue说每个任务都应该被定义为一个单独的类。任务最终会进入到队列中等待发送。

工作者(worker) 工作者负责任务的调度,比如当下一秒应该执行队列中的哪个任务了,当然它还负责监听一些信息,比如当前队列有多少个任务在等待、多少个已经完成等。

因此我的思路来了,在新建视频的时候我将要发送的模板消息放到队列中,这个过程并不负责发送,然后有一个命令行worker帮我完成具体发送工作。

先配置

在yii2中yii2-queue是以组件的形式存在,我们先来安装它。

composer require yiisoft/yii2-queue

安装后你可以在vendor的yiisoft里找到它,然后还需要简单的配置

// config/web.php
return [
    'bootstrap' => [
        'queue',
    ],
    'components' => [
        'queue' => [
            'class' => \yii\queue\file\Queue::class,
        ],
    ],
];

我们将queue加到预加载属性bootstrap中,这样worker就可以在命令行调用了,接下来配置queue组件,我们这里指定的是\yii\queue\file\Queue::class,就是用文件存放队列信息。

配置好queue的组件属性后,在代码中就可以用Yii::$app->queue来执行队列的相关功能。

构造任务类

既然yii2推荐将每个任务做成一个类,那就弄吧,yii2-queue的要求不高,你只要让这个类实现 \yii\queue\JobInterface 接口就可以了。

namespace app\queue;


class TemplateJob extends Component implements \yii\queue\JobInterface {

    ...

    /**
     * 视频订阅ID
     * @var
     */
    public $subscribeId;


    /**
     * 执行队列任务
     * @param \yii\queue\Queue $queue
     * @return boolean
     */
    public function execute($queue){
        $subscribe = Subscribe::findOne($this->subscribeId);

    }
}

代码思路如上面一样,其中execute是我们对接口JobInterface的实现,它负责具体的发送工作(任务的逻辑),而我让TemplateJob继承于Component的目的是为了方便接下来推送任务到队列方便。

记住上面的代码和你疑惑的地方,我们往下看

开始推送

有了任务类,我们只需要在相关代码中实现推送,这些模板发送任务就可以到队列中了。

// 某一段代码
$total = 0;
foreach($subscribes as $subscribe){
    ...

    Yii::$app->queue->delay(rand(5,10)*$total)->push(new TemplateJob([
        'subscribeId'=>$subscribe->id
    ]));
    
    $total++;

}

上面代码将具体的一个一个的任务推送到了队列中,因为我们的TemplateJob继承于yii2的Component,所以实例化一个TemplateJob对象时候传递的参数会被分配到对应的TemplateJob类对象的属性上,也就是xxx->subscribeId = $subscribe->id。

然后用yii2-queue给我们提供的push功能就可以推送了,如果我们不设置任务限制时间,当队列的worker发现有任务就会直接发送,但是我希望将时间分散开,因此我是用了组件的delay方法,它可以设置一个延迟时间,我是在5-10秒间取一个数字,然后乘以这个任务的排号,这里我单独使用了$total而不是foreach的$key的原因是并不是所有的$subscribe都会推送。

记住,delay很有用。

现在一个一个任务就在队列中了,生产线即将启动,我们的机器手worker即将完成调度工作。

辛苦的worker

上面我们讲了在队列中有一个很重要的概念叫做工作者(worker),它负责队列的任务执行工作。

在yii2-queue中有几种方法都可以实现worker自动执行功能,我们先来熟悉一种Supervisor。Supervisor是linux的进程监视器,它会自动启动您的控制台进程。

我们在程序命令行下键入 yii queue/listen就可以启动流水线了。

当然你还可以通过yii queue/info来看看当前队列的情况等等。

ok

一个简单的队列就实现了。

小结

对于上面简单的队列实现上很简单,但是队列有很多高级的支持,比如对不同worker的实现、对不同媒介的支持以及如何纳入第三方支持等等,我们慢慢说。

出自阿北的知识分享 http://nai8.me/article/index.html

您需要登录后才可以回复。登录 | 立即注册