在Laravel项目里,队列默认按照任务入队的先后顺序执行,但业务场景中经常会遇到需要临时调整队列任务优先级的情况,比如紧急订单处理、高优先级数据同步等需求,这时候通过命令行动态调整队列顺序会比修改业务代码更高效。

实现思路
要实现命令行动态调整队列顺序,核心思路是自定义一个Laravel命令,通过命令接收队列名称和优先级参数,然后操作队列驱动存储的任务数据,调整任务的执行顺序。这里以Redis队列驱动为例,因为Redis的有序集合特性非常适合实现优先级排序。
基础准备
首先确保项目已经配置好Redis队列驱动,在.env文件中设置队列驱动为Redis:
QUEUE_CONNECTION=redis
创建自定义命令
使用Laravel的artisan命令生成自定义命令类:
php artisan make:command AdjustQueueOrder
生成的命令类位于app/Console/Commands/AdjustQueueOrder.php,我们修改这个类的代码:
<?php
namespace AppConsoleCommands;
use IlluminateConsoleCommand;
use IlluminateSupportFacadesRedis;
class AdjustQueueOrder extends Command
{
// 命令名称
protected $signature = 'queue:adjust-order {queue : 要调整的队列名称} {priority : 优先级,数值越大优先级越高}';
// 命令描述
protected $description = '通过命令行动态调整Laravel队列任务的执行顺序';
public function handle()
{
$queue = $this->argument('queue');
$priority = $this->argument('priority');
// 验证优先级是否为数字
if (!is_numeric($priority) || $priority < 0) {
$this->error('优先级必须是大于等于0的数字');
return;
}
// 获取Redis连接
$redis = Redis::connection();
// Redis队列的任务默认存储在队列名称对应的列表中,这里先获取所有任务
$tasks = $redis->lrange("queues:{$queue}", 0, -1);
if (empty($tasks)) {
$this->info("队列 {$queue} 中没有任务");
return;
}
// 将任务存入有序集合,分数为优先级
foreach ($tasks as $task) {
$redis->zadd("queues:{$queue}:sorted", $priority, $task);
}
// 清空原队列列表
$redis->del("queues:{$queue}");
// 按照优先级从高到低取出任务,重新放入队列列表
$sortedTasks = $redis->zrevrange("queues:{$queue}:sorted", 0, -1);
foreach ($sortedTasks as $task) {
$redis->rpush("queues:{$queue}", $task);
}
// 删除临时有序集合
$redis->del("queues:{$queue}:sorted");
$this->info("队列 {$queue} 的任务顺序已调整为优先级 {$priority}");
}
}
注册命令
打开app/Console/Kernel.php文件,将自定义命令注册到$commands数组中:
<?php
namespace AppConsole;
use AppConsoleCommandsAdjustQueueOrder;
use IlluminateConsoleSchedulingSchedule;
use IlluminateFoundationConsoleKernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
protected $commands = [
AdjustQueueOrder::class,
];
protected function schedule(Schedule $schedule)
{
// 定时任务配置
}
protected function commands()
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
}
使用命令调整队列顺序
完成上述配置后,就可以通过命令行调整队列顺序了,命令格式如下:
php artisan queue:adjust-order 队列名称 优先级数值
比如要调整名为order的队列,将优先级设置为10,执行以下命令:
php artisan queue:adjust-order order 10
执行后,order队列中的所有任务都会被设置为优先级10,按照倒序重新入队,实现队列顺序的调整。
注意事项
- 该方法仅适用于Redis队列驱动,其他驱动需要根据对应存储结构修改逻辑
- 调整队列顺序时如果队列正在被消费,可能会出现任务重复执行的情况,建议在队列暂停时执行调整操作
- 如果需要为不同任务设置不同优先级,可以扩展命令参数,支持单个任务的优先级设置
扩展:为单个任务设置优先级
如果需要为队列中的单个任务设置优先级,可以修改命令支持任务ID参数,示例代码如下:
// 修改命令签名为
protected $signature = 'queue:adjust-order {queue : 要调整的队列名称} {task_id : 任务ID} {priority : 优先级,数值越大优先级越高}';
// handle方法中增加任务ID处理逻辑
public function handle()
{
$queue = $this->argument('queue');
$taskId = $this->argument('task_id');
$priority = $this->argument('priority');
// 省略参数验证逻辑
$redis = Redis::connection();
// 找到对应任务ID的任务
$tasks = $redis->lrange("queues:{$queue}", 0, -1);
$targetTask = null;
foreach ($tasks as $task) {
$taskData = json_decode($task, true);
if (isset($taskData['id']) && $taskData['id'] == $taskId) {
$targetTask = $task;
break;
}
}
if (!$targetTask) {
$this->error("队列 {$queue} 中未找到ID为 {$taskId} 的任务");
return;
}
// 后续逻辑和之前一致,仅处理目标任务即可
}
通过这种方式,就可以灵活实现Laravel队列顺序的动态调整,满足不同业务场景的需求。