我正在运行一个laravel websocket并通过 wss 建立连接。
我在服务器上运行命令,命令记录在一个文件中。每行也通过 websocket 发送到前端,以便我查看。每个 laravel-command 都有自己的文件和广播频道。
命令记录器:
class CommandLogger implements Logger {
public $commandname = '';
public $broadcast = false;
public function __construct($commandname, $broadcast = false) {
$this->commandname = Str::camel(Str::slug($commandname));
$this->broadcast = $broadcast;
}
function log($message) {
$message = Carbon::now()->format('Y-m-d H:i:s').": ".$message;
file_put_contents(storage_path("logs/commands/$this->commandname.log"), $message.PHP_EOL , FILE_APPEND | LOCK_EX);
if($this->broadcast) {
event(new CommandLogCreated($message, $this->commandname));
}
}
}
在 Vue.js 中,我使用 Echo(它实现了 pusherjs)收听:
Echo.private('logs.commands.' + command)
.listen('.command-log:created', event => {
this.log[command] += event.message + "\n";
let splitLog = this.log[command].split("\n");
let splitLength = splitLog.length;
if(splitLength > 200) {
splitLog = splitLog.slice(splitLength - 200, splitLength);
}
this.log[command] = splitLog.join('\n');
this.trigger++;
})
.error(error => {
console.log(error);
});
我遇到的问题仅在命令发送大量消息以回显时发生。
以正常速率,消息之间有一些暂停,echo 执行乒乓球并且连接仍然接收消息。
在更高的消息速率下,似乎 echo 没有发送乒乓球,我的套接字默默地停止接收数据。在它停止接收后,它开始乒乓球,好像什么都没发生一样。服务器和客户端都没有断开连接。
Websocket 消息(注意它在 205000 处停止,没有错误并恢复乒乓球):
实际命令输出(在 230000 并且仍在运行):
如果我刷新页面,我会再次收到消息。
我已经直接更新了websockers:serve
命令(vendor/beyondcode/laravel-websockets/src/Console/Commands/StartServer.php)并禁用了pongtracker:
protected function configurePongTracker()
{
//$this->loop->addPeriodicTimer(10, function () {
// $this->laravel
// ->make(ChannelManager::class)
// ->removeObsoleteConnections();
//});
}
然后我重新启动了 websocket 并再次尝试。这一次,无论我发送消息的速度有多快,echo 都会继续接收消息。
TL;博士:
我的结论是 echo 应该在从服务器接收消息之间进行乒乓球,因为目前它似乎无法这样做,并且 websocket 最终会清理连接而不会断开连接。如何强制 echo 进行乒乓球,或者确保服务器不清理连接而不冒连接失控的风险?
更新 1:
我一直在深入研究该Startserver.php
文件并发现了这一点:
public function removeObsoleteConnections(): PromiseInterface
{
if (! $this->lock()->acquire()) {
return Helpers::createFulfilledPromise(false);
}
$this->getLocalConnections()->then(function ($connections) {
foreach ($connections as $connection) {
$differenceInSeconds = $connection->lastPongedAt->diffInSeconds(Carbon::now());
if ($differenceInSeconds > 120) {
$this->unsubscribeFromAllChannels($connection);
}
}
});
return Helpers::createFulfilledPromise(
$this->lock()->forceRelease()
);
}
这就解释了为什么我停止接收消息,但没有断开连接。它只是取消订阅我正在静默收听的频道(在前端看不到这个)并保持连接活跃。
我还在github(laravel/echo) 上创建了一个问题,因为我确实认为这是不受欢迎的行为。我只是不确定问题出在 echo 还是 pusher js 中。