Laravel+Predis微服务多频道Pub/Sub报错:无效流资源
Laravel + Predis 微服务架构下Redis发布订阅报错:
fclose(): supplied resource is not a valid stream resource 问题场景
- App 1:控制器中向
timeslot频道发布事件,代码如下:
Redis::connection('timeslot')->publish('timeslot/updateStatus', json_encode([ 'timeslot' => $this->timeSlot, 'customer' => $this->file->customer_id ]));
- App 2:订阅
timeslot频道,接收事件后修改模型(此步骤正常);在模型的updated监听器中,向App 1的event频道发布Redis事件,代码如下:
static::updated(function (TimeSlot $model) { if($model->isDirty('state') && $model->state->value === 'booked'){ $result = json_encode(array_merge($model->toArray(), $model->agency->toArray())); Redis::connection('event')->publish('timeslot/booked', $result); } });
报错信息
fclose(): supplied resource is not a valid stream resource at vendor/predis/predis/src/Connection/StreamConnection.php:247 243▕ */ 244▕ public function disconnect() 245▕ { 246▕ if ($this->isConnected()) { ➜ 247▕ fclose($this->getResource()); 248▕ parent::disconnect(); 249▕ } 250▕ } 251▕
解决方法
1. 避免复用订阅进程的Redis连接
订阅进程的Redis连接处于长驻订阅状态,复用该连接执行发布操作会导致资源异常。手动创建新连接实例处理发布:
static::updated(function (TimeSlot $model) { if($model->isDirty('state') && $model->state->value === 'booked'){ $result = json_encode(array_merge($model->toArray(), $model->agency->toArray())); // 新建独立连接处理发布 $redis = new \Predis\Client(config('database.redis.event')); $redis->publish('timeslot/booked', $result); $redis->disconnect(); } });
2. 调整Redis连接的持久化配置
检查config/database.php中event连接的持久化设置,避免连接被意外回收:
'event' => [ 'host' => env('REDIS_EVENT_HOST', '127.0.0.1'), 'password' => env('REDIS_EVENT_PASSWORD', null), 'port' => env('REDIS_EVENT_PORT', '6379'), 'database' => env('REDIS_EVENT_DB', '0'), 'persistent' => false, // 关闭持久化,避免连接状态异常 ],
3. 用队列异步执行发布操作
将发布任务放入异步队列,让独立的队列进程处理Redis发布,规避订阅进程的连接冲突:
static::updated(function (TimeSlot $model) { if($model->isDirty('state') && $model->state->value === 'booked'){ $data = array_merge($model->toArray(), $model->agency->toArray()); dispatch(new PublishTimeslotBookedEvent($data)); } }); // 队列任务类 class PublishTimeslotBookedEvent implements ShouldQueue { public $data; public function __construct($data) { $this->data = $data; } public function handle() { $result = json_encode($this->data); Redis::connection('event')->publish('timeslot/booked', $result); } }
4. 升级Predis版本
该错误可能是Predis旧版本的已知bug,升级到最新稳定版修复:
composer require predis/predis:^2.2
内容的提问来源于stack exchange,提问作者Khaled sb
相关产品推荐
相关产品推荐

