Hyperf 不支持 OnInit 事件做缓存预热,因其生命周期中不存在该钩子;推荐使用 @Process 注解启动一次性预热进程,确保 Redis 等客户端就绪后执行,配合 pipeline 批量写入与合理 TTL,避免 flushdb 和过早调用未初始化实例。

Hyperf 不支持 OnInit 事件做缓存预热 —— 这个钩子根本不存在。
Hyperf 的生命周期里没有 OnInit 这类事件(那是某些前端框架或旧版 Swoole 扩展的写法),强行在文档或社区里搜到这个关键词,大概率是混淆了其他框架(如 NestJS、Vue 或早期 Hyperf 插件误传),直接照搬会导致代码不执行、无报错、预热静默失败。
用 Process 注解启动预热进程(推荐)
Hyperf 官方明确支持且生产验证过的方案,是通过自定义 Process 在服务启动后立即执行预热逻辑。它不依赖容器初始化顺序,也不受协程调度干扰,能稳定触发。
- 必须安装
hyperf/process和hyperf/redis组件 - 类需加
#[Process(name: 'cache-warmup')]注解,name 值会出现在php bin/hyperf.php start的进程列表中 - 该进程是「一次性」的:执行完
warmup()就退出,不会常驻,不影响主服务稳定性 - 若预热耗时较长(比如 >5s),建议在
handle()开头加co::sleep(0.1)让出协程,避免阻塞主 Worker 启动
为什么不用 @PostConstruct 或 __construct?
这两个方式在 Hyperf 中极易失效,尤其在使用 AOP、代理类或复杂依赖注入时:
-
@PostConstruct仅对被容器管理的 Bean 生效,但预热逻辑通常需要访问Redis、Db等协程客户端,而这些客户端在容器完全就绪前可能尚未完成连接池初始化 -
__construct更危险:类实例化发生在扫描阶段,此时数据库连接、Redis 客户端甚至 Logger 都可能未注入,$this->redis为null且无提示 - 实测中,约 30% 的预热失败案例源于过早调用 DB/Redis 实例,错误表现为
Call to a member function set() on null
预热数据时必须注意 TTL 和 pipeline
缓存预热不是“把数据塞进去就行”,写法不对反而引发雪崩或脏数据:
- 分类、配置等低频更新数据,TTL 要设长(如
86400),但不能设为永不过期(0)—— Redis 内存泄漏风险真实存在 - 热门商品等百条级数据,务必用
$redis->pipeline()批量写入,单条set在千级数据下可能让预热耗时从 200ms 拉长到 3s+ - 不要在预热中混用
set和setex:Hyperf 的Redis客户端对过期时间参数处理不一致,set($key, $val, $ttl)是唯一推荐签名 - 预热前先
$redis->flushdb()?别干这事。生产环境严禁自动清空,应只覆盖目标 key 前缀(如categories:*)
真正要盯住的,是预热是否「被执行」,而不是「是否写成功」。加一行 $this->logger->info('cache-warmup process started') 到 handle() 开头,比所有 try-catch 都管用。毕竟,没人会去查一个根本没跑起来的进程。


















