队列允许你将一个耗时的任务进行延迟处理,例如像 e-mail 发送。这能让应用程序对页面的请求有更快的响应。

即队列用于对后端服务快速响应有要求的地方。Laravel 框架提供了队列这样的系统服务,主要通过定义任务,然后将任务推送到队列上,最后通过 Laravel 命令行 php artisan queue:work 指令去处理任务。队列任务的存储主要借助于数据库或 redis,也可以使用一些三方的驱动服务。

本篇是针对 Laravel 5.2 版本 redis 驱动队列的使用说明。

修改 Laravel 队列配置文件

Laravel 队列的配置文件在 config/queue.php,返回数组中 default 约定队列使用的驱动,默认为 sync 同步。打开 .env 文件,找到 QUEUE_DRIVER 把值修改成 redis,这也对应了 connections 队列连接数组中的 redis 连接。

创建队列任务

这里通过 Artisan 命令生成:

php artisan make:job Test

会在 App/Jobs 下生成一个任务文件 Test.php,类的继承、实现及使用的 traits 都已经自动加好了,还有一个构造函数和一个 handle 处理函数。

增加一个输出日志,并使用 sleep 模拟需要一定时间处理的任务。

App/Jobs/Test.php

...
    private $info;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct($info)
    {
        $this->info = $info;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        sleep(3);
        Log::info('This is A log:' . $this->info);
    }
...

推送任务到队列

再增加一个测试路由,用来推送任务到队列上。

App/Http/routes.php

Route::get('/test', function () {
    dispatch((new \App\Jobs\Test("Today we've studied queue!"))
        ->onConnection('redis')
        ->onQueue('test')
    );
    return 'DONE!';
});

onConnection 定义推送的队列连接,这里最好不要显式的定义出来,而是使用默认队列连接,这样如果需要切换连接,可以直接修改 .env 文件就能完成。

onQueue 定义推送的队列,默认队列名称为 default,在 redis 里显示 key 值为 queues:default。在队列连接存在的情况下,使用 onQueue 定义新的队列即将任务推送到新的队列上。这里 test 队列会显示为 queues:test

需要注意,这两个方法都是在任务对象之上调用的。

使用 Supervisor 管理任务处理

队列任务的处理或者说消费是需要使用到 Artisan 命令行的。有两个相似的指令都可以使用:

php artisan queue:listen
php artisan queue:work

文档里介绍 listen 为侦听器,侦听处理队列任务;而 work 是处理队列里的第一个任务。listen 是可以后台运行的,而 work 需要加上 --daemon 才能在后台运行。

在 work 使用了后台模式运行后,在处理完每个任务前不会重新启动框架,此时的 work 会比 listen 明显的减少 CPU 的用量。所以大多使用 work 后台模式运行,每次部署代码都要使用 php artisan queue:restart 有序重启所有的 workers。

这里我使用了宝塔面板里的 Supervisor 插件,选择添加守护进程,执行目录选择项目目录,用户选择与 php-fpm 和 nginx 执行用户一致。

9D51B0D5-19EF-482f-898C-40D6EAD267BA.png

启动命令:

/usr/bin/php /www/wwwroot/example-app/artisan queue:work --queue=test --tries=1 --daemon

这边都使用了绝对路径,--daemon 自不必说,--tries 是任务出错时最多重试次数。本来 php artisan queue:work 后面还可以跟一个 connection-name(队列连接),这里可以写使用默认的队列连接 redis,也可以省略。另外 --queue= 来指定处理的队列,默认为 default

提交之后并启动守护进程,此时就可以处理队列里的任务了!

参考文档:队列 | 系统服务 |《Laravel 5.2 中文文档 5.2》| Laravel China 社区