在 Laravel 7.x 中,如何将 Generator 通过广播 broadcast 做消息推送?
我将大量的数据存储在redis中,然后查询数据时使用 Generator 作为结果,然后通过 broadcast 做消息推送,具体不知道怎么实现?
获取数据
<?php
namespace App\DataCenter;
use Generator;
use Predis\Client;
/**
* 用户相关的数据
*/
class UserData
{
/**
* 各项数据的数量
*/
public static function count(Client $redis, int $uid): array
{
return [
'messages' => $redis->scard("users:$uid:messages"),
'managed_teams' => $redis->scard("users:$uid:teams:managed"),
'served_teams' => $redis->scard("users:$uid:teams:served"),
'customer_types' => $redis->hlen("customers_types"),
'customers' => $redis->scard("users:$uid:customers"),
'districts' => $redis->scard("users:$uid:districts"),
// 可能还有其它数据
];
}
/**
* 用户的未读消息
*/
public static function messages(Client $redis, int $uid): Generator
{
$messages = $redis->smembers("users:$uid:messages");
foreach($messages as $messageId) {
yield $redis->hgetall("messages:$messageId");
}
}
/**
* 用户负责地团队
*/
public static function managedTeams(Client $redis, int $uid): Generator
{
$managedTeams = $redis->smembers("users:$uid:teams:managed");
foreach($managedTeams as $teamId) {
yield $redis->hgetall("teams:$teamId");
}
}
/**
* 用户服务地团队
*/
public static function servedTeams(Client $redis, int $uid): Generator
{
$servedTeams = $redis->smembers("users:$uid:teams:served");
foreach($servedTeams as $teamId) {
yield $redis->hgetall("teams:$teamId");
}
}
// customer_types、customers、districts 及其它数据实现方式同上
}
定义事件
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use function iterator_to_array;
use function predis;
/**
* 用户数据同步事件
*
* @example
*
* ```php
* <?php
* use App\Events\UserDataSyncEvent;
* event(new UserDataSyncEvent(getUser()->id, 'count'))
* event(new UserDataSyncEvent(getUser()->id, 'count'))
* event(new UserDataSyncEvent(getUser()->id, 'managed_teams'))
* ```
*/
class UserDataSyncEvent implements ShouldBroadcast
{
public int $uid;
public string $target;
public function __construct(int $uid, string $target)
{
$this->uid = $uid;
$this->target = $target;
}
public function broadcastOn()
{
return new Channel("user_sync.$this->uid");
}
/**
* 根据属性 $target 返回相应的数据;通过类 \App\DataCenter\UserData
* 获取的结果基本上都是生成器 \Generator ,而函数 iterator_to_array 会将
* 数据一次性加载完成,导致 PHP 占用了大量内存,也就导致了程序崩溃。
*/
public function broadcastWith()
{
$redis = predis();
switch($this->target) {
case 'districts':
return iterator_to_array(UserData::districts($redis, $this->uid));
case 'messages':
return iterator_to_array(UserData::messages($redis, $this->uid));
case 'managed_teams':
return iterator_to_array(UserData::managedTeams($redis, $this->uid));
case 'managed_teams':
return iterator_to_array(UserData::managedTeams($redis, $this->uid));
case 'customer_types':
return iterator_to_array(UserData::customerTypes($redis, $this->uid));
case 'customers':
return iterator_to_array(UserData::customers($redis, $this->uid));
// case '...':
// return iterator_to_array(UserData::...($redis, $this->uid));
default:
return UserData::count($redis, $this->uid);
}
}
}
解决方案
我希望能够像数据流一样,利用生成器一条一条的持续推送;但是我使用的是 laravel-echo-server
实现推送功能, laravel 没有办法控制WebSocket,请问如何实现?
推荐文章: