必须为每类任务配置独立redis队列驱动、channel和连接池,并通过自定义process启动对应消费者进程,投递时显式指定队列名(如'email'),才能实现物理隔离。

要在 Hyperf 3.0 中实现多个异步队列的物理隔离,避免不同业务任务互相抢占资源或因单个队列阻塞导致全局消费停滞,必须绕过默认的单一队列配置模式,为每类任务定义独立驱动、独立通道、独立进程池。
配置多个独立 Redis 队列驱动
Hyperf 的 async_queue.php 默认只支持一个 default 配置项,但可通过扩展键名方式声明多个命名队列。需手动在 config/autoload/async_queue.php 中添加额外配置块:
打开 config/autoload/async_queue.php,在 return 数组内新增 'email' 和 'report' 两个配置项,结构与 default 完全一致,但 channel 值必须不同(如 'async-email'、'async-report'),且 redis.pool 指向不同的连接池名(如 'email_redis'、'report_redis')。
【channel 名称不可重复,否则所有任务将写入同一 Redis List,失去隔离意义】
同时,在 config/autoload/redis.php 中定义对应的新连接池:'email_redis' 和 'report_redis',确保它们使用不同的 db 或不同 Redis 实例地址 —— 若共用同一 Redis 实例,至少分配不同 DB 号,否则 key 冲突会导致任务错投。
编写专用 Job 类并绑定指定队列
Job 类本身不决定投递目标,真正控制路由的是投递时指定的队列名。因此每个 Job 必须显式声明所属队列:
在 app/Job/SendEmailJob.php 中,handle() 方法保持业务逻辑不变,但投递时不调用 $job->deliver(),而是使用容器获取特定队列驱动:
$container->get(\Hyperf\AsyncQueue\Driver\RedisDriver::class)->push($job, 'email');
注意:此处第三个参数 'email' 必须与 async_queue.php 中定义的配置键名完全一致(不是 channel 名),Hyperf 会据此加载对应配置里的 channel 和 redis.pool。
同理,报表任务投递时写 push($job, 'report'),不能漏掉第二个参数,否则默认走 default 队列。
启动独立消费者进程
Hyperf 不会自动为非 default 队列拉起进程,必须手动注册 Process:
第一步:创建 app/Process/EmailQueueProcess.php,继承 \Hyperf\Process\AbstractProcess;
第二步:在 annotations 中添加 #[Process] 注解,并设置 name = "email-queue";
第三步:重写 handle() 方法,手动实例化对应队列驱动并启动消费循环:
$driver = $this->container->get(\Hyperf\AsyncQueue\Driver\RedisDriver::class);
$driver->consume('email', 1); // 第二个参数为并发数,建议设为 1~3
第四步:同样为 report 队列创建 ReportQueueProcess.php,仅修改 consume 参数为 'report';
【processes 配置项对非 default 队列无效,必须靠自定义 Process 启动,否则进程不会运行】
验证队列隔离效果
启动服务后执行:ps aux | grep 'email-queue\|report-queue',确认两个独立进程存在;
向 email 队列投递 100 条任务,同时向 report 队列投递 1 条超时任务(如在 handle() 中加 sleep(60));
观察 email 队列是否持续正常消费 —— 若停止,则说明 report 队列阻塞已影响 email,配置失败;
登录 Redis,执行 llen async-email 和 llen async-report,确认两者长度变化互不影响。











