具体以 redis
驱动为例,来介绍如何使用 laravel
队列,包括一些 laravel
队列相关的扩展知识,比如多队列的使用, queue:work
和 queue:listen
的区别等。
示例在laravel 8.24
+ php 7.4
环境运行。
配置连接和队列
在 .env
里配置好 redis
配置参数,以及 QUEUE_CONNECTION
的配置。
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=
REDIS_PORT=6379
QUEUE_CONNECTION=redis
查看 config/database.php
里的连接配置 redis
配置。
'redis' => [
...
'default' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
],
...
]
配置 config/queue.php
,这里面是 redis
连接指定队列 default
,具体参数参考文章官方文档(文章底部)。
'connections' => [
...
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => 'default',
'retry_after' => 90,
'block_for' => null,
],
...
],
以上这些配置基本就是 laravel
的默认配置。
任务模型
新建一个任务 SendMail
:
artisan make:job SendMail
会在 app/Jobs
下生成 SendMail
任务,我们来写一个假逻辑,从构造函数中获取运行需要的参数,在 handle()
中处理任务逻辑:
<?php
namespace AppJobs;
use IlluminateBusQueueable;
use IlluminateContractsQueueShouldQueue;
use IlluminateFoundationBusDispatchable;
use IlluminateQueueInteractsWithQueue;
use IlluminateQueueSerializesModels;
class SendMail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
private $data;
/**
* Create a new job instance.
* @param array $data
*/
public function __construct(array $data)
{
$this->data = $data;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
// 处理一些逻辑
doSomething($this->data);
}
}
分发任务
在业务代码中向队列分发任务:
// 向默认队列分发任务
SendMail::dispatch($data);
// 指定队列
SendMail::dispatch($data)->onQueue('high');
// 延迟分发
SendMail::dispatch($data)->delay(Carbon::now()->addMinutes(15));
// 同步调度,将会直接在当前进程中执行这个任务
SendMail::dispatchSync($data);
处理任务
直接运行命令即可处理队列里的任务。
php artisan queue:work
生产环境需要使用 supervisor
守护队列执行进程,根据需要增加进程数量。
常用运行配置项
指定队列执行优先级,每次查看有无新任务之间的间隔时间等配置项。
// 处理redis连接里 的 high 和 default 队列,high 优先级更高
php artisan queue:work redis --queue=high,default
// 新任务间隔事件
php artisan queue:work --sleep=3
// 失败重试次数3,失败后延迟执行时间5
php artisan queue:work redis --tries=3 --backoff=5
全部运行配置项
--name[=NAME] The name of the worker [default: "default"]
--queue[=QUEUE] The names of the queues to work
--daemon Run the worker in daemon mode (Deprecated)
--once Only process the next job on the queue
--stop-when-empty Stop when the queue is empty
--delay[=DELAY] The number of seconds to delay failed jobs (Deprecated) [default: "0"]
--backoff[=BACKOFF] The number of seconds to wait before retrying a job that encountered an uncaught exception [default: "0"]
--max-jobs[=MAX-JOBS] The number of jobs to process before stopping [default: "0"]
--max-time[=MAX-TIME] The maximum number of seconds the worker should run [default: "0"]
--force Force the worker to run even in maintenance mode
--memory[=MEMORY] The memory limit in megabytes [default: "128"]
--sleep[=SLEEP] Number of seconds to sleep when no job is available [default: "3"]
--timeout[=TIMEOUT] The number of seconds a child process can run [default: "60"]
--tries[=TRIES] Number of times to attempt a job before logging it failed [default: "1"]
失败任务处理
为了记录失败任务,需要一个数据表,运行:
php artisan queue:failed-table
php artisan migrate
在处理任务时,指定在遇到执行失败的重试次数
php artisan queue:work --tries=3
在任务文件中可以做更多的处理:
/**
* 计算在重试任务之前需等待的秒数,第一次重试延迟1s,第二次5s,第三次10s
*
* @return array
*/
public function backoff()
{
return [1, 5, 10];
}
/**
* 任务处理失败
*
* @param Throwable $exception
* @return void
*/
public function failed(Throwable $exception)
{
// 给用户发送失败通知, 等等...
}
任务重试命令
查看失败任务,也就是数据表“failed_jobs中的内容。
php artisan queue:failed
重试和删除失败任务
// 重试全部失败任务
php artisan queue:retry all
// 指定ID重试
php artisan queue:retry 5
// 删除一个失败任务
php artisan queue:forget 5
// 清理全部失败任务
php artisan queue:flush
扩展
多队列使用
经过测试,laravel默认有一个 default
队列,如果要使用多队列,直接在分发任务时指定队列就可以了,并不需要特殊配置,关于多队列时执行的优先级问题,看上面的处理任务常用配置项。
使用queue:work和queue:listen处理任务有什么不一样
官方更推荐使用 queue:work
来处理任务,说明是它比 queue:listen
的效率更高。
-
queue:work
使用的是已经缓存的代码当然效率更高,这使它的效率更高,但是同时queue:work
需要重启才能应用新的代码去处理任务,所以每次更新代码之后,需要重启queue:work
进程使新代码生效。 -
queue:listen
使用不存在缓存的问题,更新代码不用重启,但是效率会低一丢丢。 - 他们的执行选项几乎一样
综上,生产环境用 queue:work
,而开发环境由于代码变动频繁,性能影响也不大推荐使用 queue:listen
。
更多扩展
参考文档
-
https://learnku.com/docs/laravel/8.x/queues/9398#connections-vs-queues
-
https://laracasts.com/discuss/channels/laravel/multiple-queues-for-redis-connection
- https://stackoverflow.com/questions/41991251/what-is-the-difference-queuework-and-queuelisten/41991848