Hyperf 3.1 异步队列灰度发布需联动配置、进程、Redis通道三者原子切换:先隔离双channel并配置gray队列,再通过processes.php绑定灰度消费者,最后按用户ID哈希或中间件路由投递,并支持一键回滚。

Hyperf 3.1 应用在生产环境需对异步队列功能做灰度发布,确保新队列逻辑仅对部分用户生效、不影响主链路稳定性,同时保留快速回滚能力——这要求你不能只改代码,必须联动配置、进程、Redis 队列通道三者做原子级切换。
灰度发布前的双通道隔离准备
先为新旧队列逻辑分配独立 Redis channel 和消费进程,避免消息混投混消费。打开 config/autoload/async_queue.php,复制 default 配置块并重命名为 gray:
在 gray 配置中修改 'channel' => 'queue:gray','processes' => 0(暂不启动消费者),同时确保 'driver' 和 'redis.pool' 与 default 一致;【channel 名称必须带业务前缀且与 default 不同,否则灰度消息会进入默认队列被老消费者误处理】。
执行 php bin/hyperf.php vendor:publish hyperf/async-queue 确保配置文件已生成,否则手动创建 config/autoload/async_queue.php 并写入上述两套配置。
启用灰度消费者进程
编辑 config/autoload/processes.php,在数组末尾追加一行:
Hyperf\AsyncQueue\Process\ConsumerProcess::class . ':gray',
注意冒号后必须跟配置名 gray,这是 Hyperf v3.1+ 新增的多队列进程绑定语法;该行不可加引号包裹,否则进程无法识别配置名。
重启服务:php bin/hyperf.php start,观察控制台日志是否出现 Process[ConsumerProcess:gray] start;若无此日志,说明 processes.php 修改未生效或 gray 配置名拼写错误。
按用户 ID 实现灰度路由
方法一:在投递任务时动态选择队列通道
在 Job 类的 handle() 方法内,或投递服务中,根据用户 ID 哈希值决定投递目标:
if (crc32($userId) % 100 $job->withChannel('gray')->push();
} else {
$job->push();
}
方法二:通过中间件统一拦截控制器请求
新建 App\Middleware\GrayQueueMiddleware.php,判断请求头 X-Gray-Flag 或 cookie 中的灰度标识,调用 Container::set('async_queue.channel', 'gray') 覆盖当前协程上下文的默认 channel;【必须在任务投递前执行,且不能跨协程持久化,否则会影响其他请求】。
验证灰度消息是否进入正确通道
第一步:用 redis-cli 连接生产 Redis,执行 monitor 命令监听所有命令;
第二步:触发一次灰度用户任务投递;
第三步:观察 monitor 输出中是否出现 RPUSH queue:gray … 指令,而非 RPUSH queue …;
第四步:立即执行 LLEN queue:gray,确认返回值大于 0;若为 0,说明投递未命中 gray channel,检查 Job 实例是否调用了 withChannel() 或中间件是否生效。
一键回滚操作
步骤一:停止灰度消费者进程 → 执行 php bin/hyperf.php stop,等待进程退出;
步骤二:注释掉 config/autoload/processes.php 中 Hyperf\AsyncQueue\Process\ConsumerProcess::class . ':gray' 这一行;
步骤三:清空灰度队列积压 → 在 redis-cli 中执行 DEL queue:gray;
步骤四:重启服务 → php bin/hyperf.php start;
此时所有新任务将自动回落至 default channel,灰度通道彻底下线,无需修改任何业务代码或 Job 类。


















