Redis::subscribe()会卡住命令行,因SUBSCRIBE是阻塞式命令,使当前连接仅能处理订阅相关命令,无法执行GET/SET/DB操作;必须用独立进程、单独连接,并通过Cache::store('redis')->handler()获取原生实例调用。

直接用 Redis::subscribe() 或 Redis::publish() 就能跑通,但实际一上手就卡在连接阻塞、回调里不能查库、后台常驻崩溃这三件事上。
为什么 Redis::subscribe() 会卡住整个命令行?
因为 Redis 的 SUBSCRIBE 是阻塞式命令,一旦调用,当前连接就只能收消息,不能再执行 get、set、Db::table() 这类操作。这不是 ThinkPHP 的限制,是 Redis 协议本身的设计。
- 必须用单独的 PHP 进程跑订阅逻辑,不能和 Web 请求混在一起
- 不能在回调函数里直接调用
Db::insert()—— 因为$redis实例此时只支持subscribe/unsubscribe等四个命令 - 要用
pconnect()(或配置'persistent' => true)避免反复建连,但得配合setOption(Redis::OPT_READ_TIMEOUT, -1)防超时中断
Cache::store('redis')->handler() 和 Redis:: facade 有啥区别?
前者拿到的是原生 Redis 扩展实例,后者是 ThinkPHP 封装的门面,不支持 subscribe 等底层命令 —— 所以必须走 handler()。
-
Redis::subscribe()在 TP6 中已废弃,调用会报错 “Method subscribe does not exist” - 正确写法:
$redis = Cache::store('redis')->handler(); $redis->subscribe(['my_channel'], $callback); - 如果配置了密码,
password字段必须填对,否则subscribe会静默失败(不报错,但收不到消息)
怎么让订阅进程在后台稳定运行不退出?
靠 php think command 启动后,进程默认前台运行;一关终端就断,且无自动重连。要让它真正“常驻”,得手动补三件事。
立即学习“PHP免费学习笔记(深入)”;
- 启动时加
&放后台:php think redis:sub &,但这样日志看不到,出错难排查 - 在命令 execute 方法开头加
ini_set('max_execution_time', 0);,否则超时会退出 - 回调里别写
exit()或die(),哪怕只是调试也得删掉 —— 它会让整个订阅循环终止 - 建议加简单重连逻辑:在
subscribe外层包while(true),捕获RedisException后 sleep(1) 再重试
最易忽略的一点:Redis 默认不开启键空间通知(keyspace notification),如果你用 psubscribe 监听 __keyevent@0__:expired 这类事件,必须先在 redis.conf 里配 notify-keyspace-events Ex,或用 $redis->config('notify-keyspace-events', 'Ex') 动态设置 —— 否则永远收不到过期事件。



















