Hyperf async-queue默认非高可用,需加固三处:一是Redis连接池启用heartbeat、合理设置connect_timeout/wait_timeout;二是consumer进程配置nums≥2并用Supervisor/systemd管理;三是Job handle()中必须try/catch并手动调用retry()/release()处理执行失败。

Hyperf 的异步消息队列消费者(async-queue)默认不是高可用的——它依赖单点 Redis 和单进程消费模型,一旦进程崩溃或 Redis 故障,任务就会堆积或丢失。真要高可用,必须主动打破默认配置,重点加固三处:连接池韧性、消费进程冗余、失败任务兜底。
async-queue 的 Redis 连接池必须启用心跳与超时控制
默认的 RedisDriver 用的是框架内置连接池,但如果不显式配置心跳和超时,长时间空闲连接会被 Redis 主动断开,而 consumer 进程不会自动重连,表现为「卡住不消费」或「偶发性丢任务」。
-
connect_timeout建议设为3.0,避免阻塞启动 -
wait_timeout必须 ≤redis.timeout(即async_queue.php中的timeout),否则协程会等不到连接 -
heartbeat设为30,配合 Redis 的timeout参数(如redis.conf中timeout 60),防止连接被服务端静默回收 - 不要复用 HTTP 的 Redis 连接池;
async-queue必须单独配'pool' => 'queue',避免业务请求挤占队列连接资源
consumer 进程不能只靠 nums: 1 启动
在 @Process(nums: 1) 下,哪怕只挂一个 consumer 进程,整个队列就停摆。Hyperf 的 ConsumerProcess 本身不自带故障转移,必须靠操作系统级冗余补位。
- 在
config/autoload/process.php中,把nums设为 ≥2(如nums: 3),且确保processes在async_queue.php中为0(否则会冲突) - 用 Supervisor 或 systemd 管理进程,设置
autostart=true+autorestart=always,并监听stdout_logfile中是否出现"Process[xxx_consumer.0] start" - 别依赖
php ./bin/hyperf.php start单机启动——它不保证进程常驻;生产环境必须走进程管理器
失败任务必须手动接管重试逻辑
async-queue 的 retry_seconds 只控制「投递失败后隔多久重试」,但对「消费中抛异常」的处理极其简单:记录日志 + 移入 failed 队列,不再自动重试。这意味着你写的 handle() 里一旦 throw,任务就进黑洞。
- 所有 Job 类的
handle()必须包 try/catch,捕获后调用$this->retry(30)(单位秒)或$this->release(60)(延迟 60 秒再入队) - 不要依赖
retry_seconds全局配置——它只作用于「投递失败」,不是「执行失败」 - 定期扫描
failed队列(用redis-cli lrange hyperf:queue:failed 0 -1),人工干预或写脚本捞取重放 - 关键任务建议加 DB 记录状态表,消费前先查是否已处理,避免幂等缺失导致重复执行
高可用不是开个 nums: 2 就完事。真正难的是 Redis 连接断了怎么无声恢复、进程崩了谁来拉起、任务失败了有没有人盯日志。这些细节不提前压进配置和代码里,上线后第一波流量就能暴露单点。


















