一篇文章:

laravel中的队列服务跟其他队列服务也没有什么不同,都是最符合人类思维的最简单最普遍的流程:有一个地方存放队列信息,一个PHP进程在运行时将任务写入,另外一个PHP守护进程轮询队列信息,将达到执行要求的任务执行并删除。由于PHP是url驱动的同步语言,本身是阻塞的,所以laravel提供一个守护进程工具来查询并执行队列信息也就不足为奇了。

Laravel的queue配置文件是 /app/config/queue.php,在 Default Queue Driver 这一项中,可以选择"sync", "beanstalkd", "sqs", "iron", "redis" 五种驱动器。

配置文件:

queue.php

'redis' => array(
'driver' => 'redis',
'queue' => 'default',
),

database.php:

/*
|--------------------------------------------------------------------------
| Redis Databases
|--------------------------------------------------------------------------
|
| Redis is an open source, fast, and advanced key-value store that also
| provides a richer set of commands than a typical key-value systems
| such as APC or Memcached. Laravel makes it easy to dig right in.
|
*/

'redis' => array(

'cluster' => false,

'default' => array(
'host' => '127.0.0.1',
'port' => 6379,
'database' => 'laravelFirst',
),

),

1. sync是本地调试用的同步驱动器

2. beanstalkd 是一个专业队列服务驱动器:http://kr.github.io/beanstalkd/

3. sqs和iron是国外第三方队列服务

4. 最后一项redis给了我们一个使用redis的理由,这样我们顺便把缓存服务和session服务全部迁移到redis上了。

0. 顺便说一句,session驱动器千万别用mysql,处理时间1S不是梦,哎,看谁呢,说的就是你,1S哥!

队列服务需要专门新建任务类,作为独立类,他们不需要继承类,因为队列里的任务在执行的时候,是由PHP守护进程来独立调用的,当然如果你要use一下别的类再调用,也不会出错。之前我把很多额外服务独立到了一个单独的文件夹 /app/services 里,比如输入信息验证 validator,特殊安全验证模块等,这次queue类们就位于其中。

queue的使用非常简单,下面就是一个简单的示例:

use Queue;
Queue::push('CurlJsonQueue', [
 'url' => $url,
 'json' => $json
]);

这就是一个标准的queue压入流程了。当然,在这里我把CurlJsonQueue类放到了services根目录下,这个目录已经被我注册到composer.json的"autoload"的"classmap"中,是位于顶层命名空间中的,可以直接调用,如果需要调用非顶层命名空间,是可以写 App\OOXX 的。我们的系统需要大量和微信服务器交互,所以就独立出来了这个类。

<?php

class CurlJsonQueue extends BaseController{

public function fire($job, $data)
 {
  $url = $data['url'];
  $json = $data['json'];

parent::base_post_curl($url, $json);

$job->delete();
 }
}

这个类默认的方法是 fire() ,参数也是固定的两个 $job 和 $data,由于我在BaseController中封装了post的curl模块,所以就调用了一下。另外这里还有一个小坑,当时写base_post_curl() 的时候用的protected,导致use BaseController无效,必须继承。

通过执行上面的代码,queue中就被放入了一个新的任务,laravel通过下面的命令开启守护进程:

php artisan queue:listen

然后守护进程就开始处理队列了。此代码中的PHP命令和artisan文件的路径请自行调整。

大家可能注意到了,我们要使用的这个队列系统用到了redis和PHP命令行,如果在测试环境,加个开机启动甚至是手动启动都可以,但是在生产环境就需要更稳固的工具来守护这两个程序,我们用的是supervisor,关于supervisor的安装配置大家可以参考这篇文章: http://blog.segmentfault.com/qianfeng/1190000000532561 注意,文章里有小坑请自行去踩。。。

OK,全部配置好之后,跑起来redis和PHP命令行,整个系统就开始愉快地运行啦~

使用感受:

队列服务超好用,之前一次和app的交互流程需要6-7S,异步以后降低到2S以内,基本就是传输时间和PHP代码运行时间了,耗时的特殊操作已经异步了。不过队列服务默认1S开一个进程检查一次redis中有没有可以运行的服务,在阿里云服务器上,大约能占到单核的10%,消耗略大,而且队列处理时间相对较长,因为没有了之前同步时候的文件加载福利。不过如果有多个任务,PHP进程是会连续执行的,不会1S执行一个的啦。

下面说说坑:

1. 由于queue核心类使用了一个特殊函数,导致没有明确类型的变量会以单元素数组的形式存进json,再存进redis。解决办法就是在每一个要放进去的数据前面加上 ''. 。上面的$url和$json由于都已经在前面用引号进行了类型申明,故没做这一步操作。

2. 如果要传递url给队列,系统queue类会在每一个 / 前面加上两个 \\ 。这对于一些特殊操作可能会造成致命影响。(开玩笑,有上面那个致命么!)

------------------

我的使用,在app/service存放一个文件:

class SendEmail{
public function send($job,$data)
{ system(SEND_MAIL); $job->delete(); }
}

某个地方放入队列:

Queue::push('SendEmail@send', array('message' =>"hello world"));

有时候queue default会有2个queue:

一篇文章:

---

利用Redis可以很方便的实现一个任务队列,但是在Laravel中,Redis的队列总会出现一个任务多次执行的问题。究其原因是它写死了reserved的时长,也就是如果1分钟后任务没有执行完成,那么这个任务就会被重新放回队列。下面是队列的简单使用和执行原理。

设置

设置队列使用Redis非常容易,在app/config/queue.php中配置

...
'default' => 'redis',
...
'connections' => array(
...
'redis' => array(
'driver' => 'redis',
'queue' => 'waa',
),
),

即可。

使用

使用时不需要多配置,只要写好Queue类和其fire方法,在需要的位置出队即可。具体方法可以看这里

class SendEmail {

    public function fire($job, $data)
{
//
$job->delete();
} } Queue::push('SendEmail@send', array('message' => $message));

流程

Laravel利用artisan命令来执行出队操作,然后进行任务的执行。方法调用如下:

  1. artisan queue:work
  2. WorkerCommand:fire()
  3. Worker:pop()
  4. Worker:getNextJob()
  5. RedisQueue:pop()
  6. Worker:process()

我遇到的问题就在这里,在RedisQueue:pop()方法中,有这样一句:

$this->redis->zadd($queue.':reserved', $this->getTime() + 60, $job);

这里将当前执行的任务放到另外一个reserved队列中,超时时间是60s。也就是说,如果60s后这个任务没有被删除掉,则任务会重新被放入队列中来。因此,在实际的使用过程中,任务很可能被多次执行。解决的办法是

class SendEmail {

    public function fire($job, $data)
{
$job->delete();
// job
} }

即先删除这个任务,再开始执行任务

参考:http://yansu.org/2014/04/11/redis-queue-in-laravel.html

supervisor管理queue:http://yansu.org/2014/03/22/managing-your-larrvel-queue-by-supervisor.html

laravel queue队列使用的更多相关文章

  1. 使用Laravel的队列实现系统通知、

    使用Laravel的队列实现系统通知. 第一步:创建 jobs表的migrate php artisan queue:table 第二步:创建jobs 表 php artisan migrate 第三 ...

  2. Laravel Queues 队列应用实战

    队列,顾名思义,排着队等着做事情.在生活场景中,凡是排队的人,都是带有目的性的.要完成某件事情,才去排队的,要不没有谁会闲到排队玩儿.而在软件应用层面,队列是什么,队列有什么优点,我们什么时候需要用队 ...

  3. C#基础---Queue(队列)的应用

       Queue队列,特性先进先出. 在一些项目中我们会遇到对一些数据的Check,如果数据不符合条件将会把不通过的信息返回到界面.但是对于有的数据可能会Check很多条件,如果一个数据一旦很多条件不 ...

  4. 第19章 queue队列容器

    /* 第19章 queue队列容器 19.1 queue技术原理 19.2 queue应用基础 19.3 本章小结 */ // 第19章 queue队列容器 // 19.1 queue技术原理 // ...

  5. atitit. java queue 队列体系and自定义基于数据库的队列总结o7t

    atitit. java queue 队列体系and自定义基于数据库的队列总结o7t 1. 阻塞队列和非阻塞队列 1 2. java.util.Queue接口, 1 3. ConcurrentLink ...

  6. C#部分---特殊集合:stack栈集合、queue队列集合、哈希表集合。

    1.stack栈集合:又名 干草堆集合 栈集合 特点:(1)一个一个赋值 一个一个取值(2)先进后出实例化 初始化 Stack st = new Stack(); //添加元素用push st.Pus ...

  7. 实现一个线程安全的Queue队列

    使用装饰者模式实现一个线程安全的Queue队列. public class SynchronizedQueue<E> implements Queue<E>, Serializ ...

  8. Python自动化运维之16、线程、进程、协程、queue队列

    一.线程 1.什么是线程 线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位. 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行 ...

  9. Stack集合 Queue队列集合 Hashtable哈希表

    Stack集合 干草堆集合 栈集合 栈;stack,先进后出,一个一个赋值,一个一个取值,安装顺序来. 属性和方法 实例化 初始化 Stack st = new Stack(); 添加元素 个数 Co ...

随机推荐

  1. 15.3.14 DP练习2

    拦截导弹 题目 某国为了防御敌国的导弹突击,发展出一种导弹拦截系统. 可是这样的导弹拦截系统有一个缺陷:尽管它的第一发炮弹可以到达随意的高度.可是以后每一发炮弹都不能高于前一发的高度. 某天,雷达捕捉 ...

  2. TCP/IP详解读书笔记:ARP-地址解析协议

    地址解析为两种不同的地址形式提供映射:32bit的IP和数据链路层使用的任何类型的地址. 当一台主机把以太网数据帧发送到位于同一局域网的另一台主机,是根据48bit的以太网地址而不是IP地址.设备驱动 ...

  3. FastDFS安装详解

    1.安装环境 os:centos6.5 Fastdfs版本:FastDFS_v5.08.tar.gz 下载地址:https://sourceforge.net/projects/fastdfs/fil ...

  4. JQ实现吸顶效果代码

    吸顶下过代码跟简单几行代码就可以了 如果滚动的军力大于100,就改变导航的定位方式,否则就默认 $(function(){         $(window).scroll(function(){   ...

  5. 什么是ORM,以及在php上的使用?

    ORM:object relation mapping,即对象关系映射,简单的说就是对象模型和关系模型的一种映射.为什么要有这么一个映射?很简单,因为现在的开发语言基本都是oop的,但是传统的数据库却 ...

  6. 关联数据和formatter问题-easyui+微型持久化工具

    控制器 using System; using System.Collections.Generic; using System.Linq; using System.Web; using Syste ...

  7. linux下的线程池

    什么时候需要创建线程池呢?简单的说,如果一个应用需要频繁的创建和销毁线程,而任务执行的时间又非常短,这样线程创建和销毁的带来的开销就不容忽视,这时也是线程池该出场的机会了.如果线程创建和销毁时间相比任 ...

  8. 《linux 内核全然剖析》 include/asm/io.h

    include/asm/io.h #define outb(value,port) \ __asm__ ("outb %%al,%%dx"::"a" (valu ...

  9. 如何列出github上最多star/fork的project

    访问此页面进行搜索: https://github.com/search/advanced 再参考github高级搜索语法: https://help.github.com/articles/sear ...

  10. IOS开发之 -- 线程初识

    对于开发者来说,多线程永远有这一层神秘的色彩,似乎是一到迈步过去的坎,在同步.异步.串行.并行.死锁这几个名字当中,逐渐的放弃治疗,下面就多线程,谈一下自己的认识,理解的肯定不全面,只是一些简单的皮毛 ...