Laravel 5.2 使用 redis 队列
队列允许你将一个耗时的任务进行延迟处理,例如像 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 执行用户一致。
启动命令:
/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
。
提交之后并启动守护进程,此时就可以处理队列里的任务了!