Laravel服务端事件(SSE)中$lastrec变量无法更新的问题排查
Laravel SSE 重复获取旧数据问题解决
问题本质
你用控制器私有变量$lastrec记录最后处理的ID,但每次SSE连接请求都会创建新的控制器实例,之前的$lastrec值会被重置为0,根本没法跨循环/跨请求保存状态。
解决思路:用持久化存储存lastrec
把$lastrec从控制器私有变量换成缓存、Redis或者数据库这类持久化存储,就能跨请求保持状态了,下面给具体实现:
方案1:用Laravel缓存(最简单)
直接替换变量读写为缓存操作:
public function streamUpdates() { // 从缓存取上次的记录ID,默认0 $lastrec = Cache::get('sse_last_record_id', 0); return response()->stream(function () use (&$lastrec) { while (true) { // 只查ID大于lastrec的新记录 $newzRecords = Newz::where('id', '>', $lastrec)->orderBy('id')->get(); if ($newzRecords->isNotEmpty()) { foreach ($newzRecords as $record) { // 关联业务表取数据 $fullData = match($record->type) { 'TODOS' => TODOS::find($record->business_id), 'MEMOS' => MEMOS::find($record->business_id), default => null }; // 发送SSE事件 echo "event: new-data\n"; echo "data: " . json_encode($fullData) . "\n\n"; ob_flush(); flush(); // 更新缓存和本地变量 Cache::put('sse_last_record_id', $record->id, now()->addDay()); $lastrec = $record->id; } } // 每秒查一次,避免占满CPU sleep(1); } }, 200, [ 'Content-Type' => 'text/event-stream', 'Cache-Control' => 'no-cache', 'Connection' => 'keep-alive', ]); }
方案2:用Redis(高并发场景)
如果项目已经用Redis,用法和缓存类似,只是指定驱动:
// 初始化 $lastrec = Redis::get('sse_last_record_id') ?? 0; // 更新时 Redis::set('sse_last_record_id', $record->id);
方案3:用数据库存储(需要持久化到磁盘)
建个简单的配置表sse_configs(字段key、value),专门存这个ID:
// 初始化,没有就创建默认值0 $config = SseConfig::firstOrCreate(['key' => 'last_record_id'], ['value' => 0]); $lastrec = (int)$config->value; // 更新时 $config->update(['value' => $record->id]);
额外提醒
- 一定要设置正确的SSE响应头,不然浏览器可能会缓存数据或者断开连接
- 休眠时间可以根据业务调整,比如数据更新不频繁就设成5秒
- 多服务器部署的话,别用本地缓存,必须用Redis这类分布式存储,不然不同节点的记录ID会不一致
内容的提问来源于stack exchange,提问作者karmel
相关产品推荐
相关产品推荐

