在Laravel应用上线或者数据更新后,执行缓存预热可以快速将常用数据加载到缓存中,减少用户首次访问的等待时间。但默认的队列任务执行顺序是按照入队时间排列的,如果此时有大量其他普通任务在队列中,预热任务可能会被延迟执行,无法达到预期效果。因此为缓存预热任务指定高优先级是很有必要的。

通过队列优先级实现缓存预热任务高优先级
Laravel的队列系统支持为不同任务指定不同的优先级,核心思路是配置多个不同优先级的队列,将缓存预热任务推送到高优先级队列中。
1. 配置队列优先级
首先修改队列配置文件config/queue.php,以Redis驱动为例,在connections的redis配置中添加队列优先级相关配置:
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => env('REDIS_QUEUE', 'default'),
// 配置队列优先级,高优先级队列在前
'priority' => ['high', 'default', 'low'],
'retry_after' => 90,
'block_for' => null,
],
2. 创建缓存预热任务类
使用Artisan命令创建预热任务类:
php artisan make:job CacheWarmupJob
编辑生成的app/Jobs/CacheWarmupJob.php文件,实现预热逻辑:
<?php
namespace AppJobs;
use IlluminateBusQueueable;
use IlluminateContractsQueueShouldQueue;
use IlluminateFoundationBusDispatchable;
use IlluminateQueueInteractsWithQueue;
use IlluminateQueueSerializesModels;
use IlluminateSupportFacadesCache;
use AppModelsArticle;
class CacheWarmupJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
// 指定任务使用高优先级队列
public $queue = 'high';
/**
* 执行缓存预热任务
*/
public function handle()
{
// 预热热门文章缓存
$hotArticles = Article::where('is_hot', 1)->limit(20)->get();
Cache::put('hot_articles', $hotArticles, 3600);
// 预热首页配置缓存
$homeConfig = Config::where('type', 'home')->first();
Cache::put('home_config', $homeConfig, 86400);
}
}
3. 启动队列处理器时指定优先级顺序
启动队列处理器时,需要按照优先级顺序监听队列,确保高优先级队列的任务先被执行:
php artisan queue:work redis --queue=high,default,low
通过任务调度优先级设置预热任务
如果是通过任务调度执行缓存预热,也可以为调度任务指定优先级,避免被其他调度任务阻塞。
1. 定义调度任务
在app/Console/Kernel.php的schedule方法中配置预热任务:
<?php
namespace AppConsole;
use IlluminateConsoleSchedulingSchedule;
use IlluminateFoundationConsoleKernel as ConsoleKernel;
use AppJobsCacheWarmupJob;
class Kernel extends ConsoleKernel
{
protected function schedule(Schedule $schedule)
{
// 每小时执行一次缓存预热,设置高优先级
$schedule->job(new CacheWarmupJob())
->hourly()
->onQueue('high') // 指定使用高优先级队列
->withoutOverlapping(); // 避免任务重复执行
}
protected function commands()
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
}
结合Redis的ZSET实现自定义优先级
如果需要更灵活的优先级控制,可以结合Redis的有序集合(ZSET)实现自定义优先级逻辑,优先级数值越大,执行顺序越靠前。
<?php
namespace AppServices;
use IlluminateSupportFacadesRedis;
use AppJobsCacheWarmupJob;
class CacheWarmupService
{
/**
* 添加高优先级缓存预热任务
*/
public function addHighPriorityWarmupTask()
{
$taskData = [
'job' => CacheWarmupJob::class,
'data' => ['type' => 'hot_data']
];
// 优先级设为100,高于普通任务的优先级
Redis::zadd('cache_warmup_tasks', 100, json_encode($taskData));
}
/**
* 消费预热任务
*/
public function consumeWarmupTask()
{
// 获取优先级最高的任务
$task = Redis::zrevrange('cache_warmup_tasks', 0, 0);
if (!empty($task)) {
$taskData = json_decode($task[0], true);
// 分发任务到队列
dispatch(new $taskData['job']($taskData['data']));
// 移除已执行的任务
Redis::zrem('cache_warmup_tasks', $task[0]);
}
}
}
注意事项
- 高优先级队列的任务如果过多,可能会导致低优先级队列的任务长时间无法执行,需要根据业务场景合理分配任务优先级。
- 队列处理器的
--queue参数中队列的顺序决定了执行优先级,高优先级队列要放在前面。 - 如果使用Redis作为缓存和队列驱动,要确保Redis服务运行正常,避免预热任务执行失败。