• 在yii2论坛中看到一个关于队列的帖子,感觉不错.http://www.yiichina.com/extension/1084

    (注:SendMail 错写为 SendMial,粘贴时要注意了.)

  • 在使用的过程中觉得挺好的,建议看一下关于队列的原理.

  • shmilyzxt/yii2-queue 简单解释:

  1. 我用的yii2高级版,我们从配置开始看代码,这里我用的是mysql队列,首先配置文件,我把queue配置项写在根目录common\config\main-local.php下的 components数组下,更改一下数据库配置.复制composer安装后复制

    vendor\shmilyzxt\yii2-queue\jobs\jobs.sql

    vendor\shmilyzxt\yii2-queue\failed\failed.sql

    2个sql文件到数据库中建立队列数据表和执行任务失败时的数据表.

  2. 推送任务开始语法:\Yii::$app->queue->pushOn(new SendMial(),['email'=>'49783121@qq.com','title'=>'test','content'=>'email test'],'email'); 我们到vendor\shmilyzxt\queue\queues\DatabaseQueue.php去看看代码,pushOn()方法写在了DatabaseQueue类的父类vendor\shmilyzxt\queue\base\Queue.php中:

//入队列
public function pushOn($job, $data = '', $queue = null)
{
//canPush 检查队列是否已达最大任务量
if ($this->canPush()) {
//beforePush 入队列前的事件
$this->trigger(self::EVENT_BEFORE_PUSH);
//入队列
$ret = $this->push($job, $data, $queue);
//afterPush 入队列后的事件
$this->trigger(self::EVENT_AFTER_PUSH);
return $ret;
} else {
throw new \Exception("max jobs number exceed! the max jobs number is {$this->maxJob}");
}
}

注释:这里最好去看看yii2 event事件类,http://www.digpage.com/event.html

关于入队列: $this->push($job, $data, $queue);,这里在配合queue类文件查看,相关函数跳转,处理一下数据记录到数据库中.(函数走向:getQueue()-->createPayload()-->pushToDatabase()),pushOn()最终返回数据插入数据库的结果,成功$ret是1.

3.后台运行命令处理队列,例:php ./yii worker/listen default 10 128 3 0 其中default是队列的名称,上面推送了一个email队列 应该改为email.

启动命令后,我们来看代码:首先执行:WorkerController控制器 actionListen方法,我们跟着代码进入到 vendor\shmilyzxt\queue\Worker.php -- listen方法中,这里其实就是一直在循环,执行操作队列的任务:

/**
* 启用一个队列后台监听任务
* @param Queue $queue
* @param string $queueName 监听队列的名称(在pushon的时候把任务推送到哪个队列,则需要监听相应的队列才能获取任务)
* @param int $attempt 队列任务失败尝试次数,0为不限制
* @param int $memory 允许使用的最大内存
* @param int $sleep 每次检测的时间间隔
*/
public static function listen(Queue $queue, $queueName = 'default', $attempt = 10, $memory = 512, $sleep = 3, $delay = 0){
while (true){
try{
//DatabaseQueue从数据库队列取出一个可用任务(实例),并且更新任务
$job = $queue->pop($queueName);
}catch (\Exception $e){
throw $e;
continue;
} if($job instanceof Job){
//判断执行错误的次数是否大于传入的执行次数
if($attempt > 0 && $job->getAttempts() > $attempt){
$job->failed();
}else{
try{
//throw new \Exception("test failed");
$job->execute(); }catch (\Exception $e){
//执行失败,判断是否被删除,重新入队
if (! $job->isDeleted()) {
$job->release($delay);
}
}
}
}else{
self::sleep($sleep);
} if (self::memoryExceeded($memory)) {
self::stop();
}
}
}

注释:在$queue->pop($queueName);vendor\shmilyzxt\queue\queues\DatabaseQueue.php方法内使用事务执行SQL,并且创建vendor\shmilyzxt\queue\jobs\DatabaseJob.php的实例

	//取出一个任务
public function pop($queue = null)
{
$queue = $this->getQueue($queue); if (!is_null($this->expire)) {
//$this->releaseJobsThatHaveBeenReservedTooLong($queue);
} $tran = $this->connector->beginTransaction();
//判断是否有一个可用的任务需要执行
if ($job = $this->getNextAvailableJob($queue)) {
$this->markJobAsReserved($job->id);
$tran->commit(); $config = array_merge($this->jobEvent, [
'class' => 'shmilyzxt\queue\jobs\DatabaseJob',
'queue' => $queue,
'job' => $job,
'queueInstance' => $this,
]); return \Yii::createObject($config); }
$tran->commit();
return false;
}

至于:$job->execute();DatabaseJob继承父类Job执行的,顺着代码找下去是yii\base\Component trigger执行的事件,

/**
* 执行任务
*/
public function execute()
{
$this->trigger(self::EVENT_BEFORE_EXECUTE, new JobEvent(["job" => $this, 'payload' => $this->getPayload()]));//beforeExecute 执行任务之前的一个事件 在JobEvent中并没有什么可执行的代码
$this->resolveAndFire();//真正执行的任务的方法
}
 /**
* 真正任务执行方法(调用hander的handle方法)
* @param array $payload
* @return void
*/
protected function resolveAndFire()
{
$payload = $this->getPayload();
$payload = unserialize($payload); //反序列化数据
$type = $payload['type'];
$class = $payload['job']; if ($type == 'closure' && ($closure = (new Serializer())->unserialize($class[1])) instanceof \Closure) {
$this->handler = $this->getHander($class[0]);
$this->handler->closure = $closure;
$this->handler->handle($this, $payload['data']);
} else if ($type == 'classMethod') {
$payload['job'][0]->$payload['job'][1]($this, $payload['data']);
} else if ($type == 'staticMethod') {
$payload['job'][0]::$payload['job'][1]($this, $payload['data']);
} else {//执行的`SendMail`类的`handle($job,$data)`方法
$this->handler = $this->getHander($class);
$this->handler->handle($this, $payload['data']);
} //执行完任务后删除
if (!$this->isDeletedOrReleased()) {
$this->delete();
}
}

最后到了执行的SendMail类的handle($job,$data),在这里就是推送到队列的对象和数据,接着就是我们的处理逻辑了.

public function handle($job,$data)
{
if($job->getAttempts() > 3){
$this->failed($job);
} $payload = $job->getPayload();
echo '<pre>';print_r($payload);
//$payload即任务的数据,你拿到任务数据后就可以执行发邮件了
//TODO 发邮件
}

yii2 队列 shmilyzxt/yii2-queue 简介的更多相关文章

  1. 消息队列(Message Queue)简介及其使用

    消息队列(Message Queue)简介及其使用 摘要:利用 MSMQ(Microsoft Message Queue),应用程序开发人员可以通过发送和接收消息方便地与应用程序进行快速可靠的通信.消 ...

  2. 深入浅出 Java Concurrency (19): 并发容器 part 4 并发队列与Queue简介[转]

    Queue是JDK 5以后引入的新的集合类,它属于Java Collections Framework的成员,在Collection集合中和List/Set是同一级别的接口.通常来讲Queue描述的是 ...

  3. JavaScript实现队列结构(Queue)

    JavaScript实现队列结构(Queue) 一.队列简介 队列是是一种受限的线性表,特点为先进先出(FIFO:first in first out). 受限之处在于它只允许在表的前端(front) ...

  4. 消息队列(Message Queue)基本概念(转)

    背景 之前做日志收集模块时,用到flume.另外也有的方案,集成kafaka来提升系统可扩展性,其中涉及到消息队列当时自己并不清楚为什么要使用消息队列.而在我自己提出的原始日志采集方案中不适用消息队列 ...

  5. JavaSE中Collection集合框架学习笔记(2)——拒绝重复内容的Set和支持队列操作的Queue

    前言:俗话说“金三银四铜五”,不知道我要在这段时间找工作会不会很艰难.不管了,工作三年之后就当给自己放个暑假. 面试当中Collection(集合)是基础重点.我在网上看了几篇讲Collection的 ...

  6. c/c++ linux 进程间通信系列6,使用消息队列(message queue)

    linux 进程间通信系列6,使用消息队列(message queue) 概念:消息排队,先进先出(FIFO),消息一旦出队,就从队列里消失了. 1,创建消息队列(message queue) 2,写 ...

  7. Java分布式:消息队列(Message Queue)

    Java分布式:消息队列(Message Queue) 引入消息队列 消息,是服务间通信的一种数据单位,消息可以非常简单,例如只包含文本字符串:也可以更复杂,可能包含嵌入对象.队列,是一种常见的数据结 ...

  8. 优先队列——二项队列(binominal queue)

    [0]README 0.1) 本文文字描述部分转自 数据结构与算法分析, 旨在理解 优先队列——二项队列(binominal queue) 的基础知识: 0.2) 本文核心的剖析思路均为原创(inse ...

  9. 消息队列(Message Queue)基本概念

    背景 之前做日志收集模块时,用到flume.另外也有的方案,集成kafaka来提升系统可扩展性,其中涉及到消息队列当时自己并不清楚为什么要使用消息队列.而在我自己提出的原始日志采集方案中不适用消息队列 ...

随机推荐

  1. ztree学习笔记(一)

    在项目当中,经常会用到ztree树形插件,之前做的几个项目当中都用到了这个插件,感觉功能还是很强大的,而且在网上还找到了中文的API,因为项目中的树形结构不是自己做的,所以现在从头学习一下,并且记录一 ...

  2. Tenacity——Exception Retry 从此无比简单

    Python 装饰器装饰类中的方法这篇文章,使用了装饰器来捕获代码异常.这种方式可以让代码变得更加简洁和Pythonic. 在写代码的过程中,处理异常并重试是一个非常常见的需求.但是如何把捕获异常并重 ...

  3. Rails核心组件

    Action Pack 包含Action Controller,Action View,Action Dispatch 封装了MVC的VC功能 Action Mailer 开发电子邮件服务的框架 Ac ...

  4. CoreLocation 框架

    获取设备的地理位置和方向 一.概述 CoreLocation框架,它提供了如下几种服务 确定设备的地理位置 高度 方向 或到附近 iBeacon 的相对位置. 这个框架使用所有可用的车载硬件.如 Wi ...

  5. sql 注入命令大全

    1.判断有无注入点 ; and 1=1 and 1=2 2.猜表一般的表的名称无非是admin adminuser user pass password 等.. and 0<>(selec ...

  6. python 标准库 -- re

    re 正则表达式 语法 import re m = re.search('[0-9]','abc4def67') # 匹配字符及匹配范围 print m.group(0) # 返回匹配结果 re.se ...

  7. BOM API

    原文链接http://www.jb51.net/article/55851.htm 我们都知道, javascript 有三部分构成,ECMAScript,DOM和BOM,根据宿主(浏览器)的不同,具 ...

  8. JDBC 数据库连接操作——实习第三天

    今天开始了比较重量级的学习了,之前都是对于Java基础的学习和回顾.继续上篇的话题,<谁动了我的奶酪>,奉献一句我觉得比较有哲理的话:"学会自嘲了,而当人们学会自嘲,能够嘲笑自己 ...

  9. Xamarin开发笔记—设备类&第三方弹窗的使用和注意事项

    一.设备类是Xamarin重要开发组成部分,下面介绍一下设备类的主要用法: //唤醒打电话 Device.OpenUri(new Uri("tel:180xxxxxxxx")); ...

  10. Codeforces Round #419 (Div. 2)

    1.题目A:Karen and Morning 题意: 给出hh:mm格式的时间,问至少经过多少分钟后,该时刻为回文字符串? 思路: 简单模拟,从当前时刻开始,如果hh的回文rh等于mm则停止累计.否 ...