Use a RedisLock to avoid race conditions.

This commit is contained in:
Alex Renoki 2020-08-27 22:28:22 +03:00
parent 0f4928f93a
commit ee8681a459
1 changed files with 30 additions and 17 deletions

View File

@ -5,6 +5,7 @@ namespace BeyondCode\LaravelWebSockets\Statistics\Logger;
use BeyondCode\LaravelWebSockets\Apps\App; use BeyondCode\LaravelWebSockets\Apps\App;
use BeyondCode\LaravelWebSockets\Statistics\Drivers\StatisticsDriver; use BeyondCode\LaravelWebSockets\Statistics\Drivers\StatisticsDriver;
use BeyondCode\LaravelWebSockets\WebSockets\Channels\ChannelManager; use BeyondCode\LaravelWebSockets\WebSockets\Channels\ChannelManager;
use Illuminate\Cache\RedisLock;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
class RedisStatisticsLogger implements StatisticsLogger class RedisStatisticsLogger implements StatisticsLogger
@ -115,24 +116,26 @@ class RedisStatisticsLogger implements StatisticsLogger
*/ */
public function save() public function save()
{ {
foreach ($this->redis->smembers('laravel-websockets:apps') as $appId) { $this->lock()->get(function () {
if (! $statistic = $this->redis->hgetall($this->getHash($appId))) { foreach ($this->redis->smembers('laravel-websockets:apps') as $appId) {
continue; if (! $statistic = $this->redis->hgetall($this->getHash($appId))) {
continue;
}
$this->driver::create([
'app_id' => $appId,
'peak_connection_count' => $statistic['peak_connection_count'] ?? 0,
'websocket_message_count' => $statistic['websocket_message_count'] ?? 0,
'api_message_count' => $statistic['api_message_count'] ?? 0,
]);
$currentConnectionCount = $this->channelManager->getConnectionCount($appId);
$currentConnectionCount === 0
? $this->resetAppTraces($appId)
: $this->resetStatistics($appId, $currentConnectionCount);
} }
});
$this->driver::create([
'app_id' => $appId,
'peak_connection_count' => $statistic['peak_connection_count'] ?? 0,
'websocket_message_count' => $statistic['websocket_message_count'] ?? 0,
'api_message_count' => $statistic['api_message_count'] ?? 0,
]);
$currentConnectionCount = $this->channelManager->getConnectionCount($appId);
$currentConnectionCount === 0
? $this->resetAppTraces($appId)
: $this->resetStatistics($appId, $currentConnectionCount);
}
} }
/** /**
@ -190,4 +193,14 @@ class RedisStatisticsLogger implements StatisticsLogger
{ {
return "laravel-websockets:app:{$appId}"; return "laravel-websockets:app:{$appId}";
} }
/**
* Get a new RedisLock instance to avoid race conditions.
*
* @return \Illuminate\Cache\CacheLock
*/
protected function lock()
{
return new RedisLock($this->redis, 'laravel-websockets:lock', 0);
}
} }