必须使用async-queue投递路径而非手动协程,安装composer require hyperf/async-queue、生成配置、启用consumerprocess进程、创建job类并选择传统或注解方式投递,缺一不可。

要在Hyperf 2.2中快速实现耗时操作不阻塞接口,比如下单后发短信、写日志、同步库存,必须把任务扔进异步队列——不是靠手动起协程,而是走标准的async-queue投递路径,否则任务不会被ConsumerProcess捕获执行。
安装并生成基础配置
执行命令安装组件:composer require hyperf/async-queue
运行发布命令生成配置文件:php bin/hyperf.php vendor:publish hyperf/async-queue。该命令会在 config/autoload/async_queue.php 创建默认配置,若目录不存在或权限不足,命令会静默失败,【务必确认文件已生成】。
检查 config/autoload/async_queue.php 是否存在,内容应包含 'driver' => Hyperf\AsyncQueue\Driver\RedisDriver::class 等字段;若为空或报错,说明 Redis 连接池未就绪,需先配好 config/autoload/redis.php。
启用异步消费进程
打开 config/autoload/processes.php,确保数组中包含 ConsumerProcess 类:
return [Hyperf\AsyncQueue\Process\ConsumerProcess::class];
这一步不可省略——没有它,队列消息永远无人监听。Hyperf 启动时会根据此列表拉起对应进程,【processes 配置项必须大于 0】,否则即使代码写对,任务也只会堆积在 Redis channel 里不动。
创建可执行的 Job 类
在 app/Job 目录下新建 SendSmsJob.php:
declare(strict_types=1);
namespace App\Job;
use Hyperf\AsyncQueue\Job;
class SendSmsJob extends Job { public $phone; public $content; public function __construct(string $phone, string $content) { $this->phone = $phone; $this->content = $content; } public function handle() { // 实际调用短信 SDK 或写入日志 file_put_contents('/tmp/sms.log', "[{$this->phone}] {$this->content}\n", FILE_APPEND); } }
注意:构造函数中只传原始数据(字符串、数字、数组),【严禁传入 PDO 实例、Container 对象等含资源句柄的类】,序列化时会失败且无明确报错。
两种投递方式任选其一
方法一:传统服务层投递
新建 app/Service/QueueService.php,注入 Hyperf\AsyncQueue\Driver\DriverInterface,调用 push 方法:
public function sendSms(string $phone, string $content): void { $this->driver->push(new SendSmsJob($phone, $content)); }
方法二:注解式一键投递(更轻量)
在任意 Service 或 Controller 方法上加 #[AsyncQueueMessage] 注解:
#[AsyncQueueMessage] public function sendSms(string $phone, string $content): void { file_put_contents('/tmp/sms.log', "[{$phone}] {$content}\n", FILE_APPEND); }
该方式无需定义 Job 类,参数自动序列化,但仅限于简单逻辑;复杂业务仍推荐 Job 方式,便于复用与单元测试。
验证任务是否真正执行
第一步:启动服务,观察控制台输出 —— 必须看到类似 Process[ConsumerProcess] start 的日志行,表示消费者进程已拉起。
第二步:调用投递逻辑(如访问一个触发 QueueService::sendSms() 的 API 接口)。
第三步:立即检查 /tmp/sms.log 是否新增内容;若 5 秒内无记录,说明 Redis 通道不通或 Consumer 进程异常退出,此时执行 ps aux | grep ConsumerProcess 查看进程是否存在。
第四步:确认 Redis 中 key queue(或你配置的 channel 值)是否有数据:redis-cli lrange queue 0 -1。有数据但 log 无输出,大概率是 handle() 内部抛了未捕获异常,需检查 Hyperf 日志目录下的 hyperf.log。











