Skip to content
This repository was archived by the owner on Feb 7, 2024. It is now read-only.

[fix] Fix stale data #633

Merged
merged 6 commits into from
Dec 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/Contracts/StatisticsCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,13 @@ public function getStatistics(): PromiseInterface;
* @return PromiseInterface[\BeyondCode\LaravelWebSockets\Statistics\Statistic|null]
*/
public function getAppStatistics($appId): PromiseInterface;

/**
* Remove all app traces from the database if no connections have been set
* in the meanwhile since last save.
*
* @param string|int $appId
* @return void
*/
public function resetAppTraces($appId);
}
18 changes: 18 additions & 0 deletions src/Statistics/Collectors/MemoryCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ public function save()
continue;
}

if ($statistic->shouldHaveTracesRemoved()) {
$this->resetAppTraces($appId);

continue;
}

$this->createRecord($statistic, $appId);

$this->channelManager
Expand Down Expand Up @@ -142,6 +148,18 @@ public function getAppStatistics($appId): PromiseInterface
);
}

/**
* Remove all app traces from the database if no connections have been set
* in the meanwhile since last save.
*
* @param string|int $appId
* @return void
*/
public function resetAppTraces($appId)
{
unset($this->statistics[$appId]);
}

/**
* Find or create a defined statistic for an app.
*
Expand Down
8 changes: 7 additions & 1 deletion src/Statistics/Collectors/RedisCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ public function save()
$appId, Helpers::redisListToArray($list)
);

if ($statistic->shouldHaveTracesRemoved()) {
return $this->resetAppTraces($appId);
}

$this->createRecord($statistic, $appId);

$this->channelManager
Expand Down Expand Up @@ -265,7 +269,7 @@ public function resetStatistics($appId, int $currentConnectionCount)
->getPublishClient()
->hset(
$this->channelManager->getRedisKey($appId, null, ['stats']),
'peak_connections_count', $currentConnectionCount
'peak_connections_count', max(0, $currentConnectionCount)
);

$this->channelManager
Expand All @@ -292,6 +296,8 @@ public function resetStatistics($appId, int $currentConnectionCount)
*/
public function resetAppTraces($appId)
{
parent::resetAppTraces($appId);

$this->channelManager
->getPublishClient()
->hdel(
Expand Down
14 changes: 13 additions & 1 deletion src/Statistics/Statistic.php
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,23 @@ public function apiMessage()
public function reset(int $currentConnectionsCount)
{
$this->currentConnectionsCount = $currentConnectionsCount;
$this->peakConnectionsCount = $currentConnectionsCount;
$this->peakConnectionsCount = max(0, $currentConnectionsCount);
$this->webSocketMessagesCount = 0;
$this->apiMessagesCount = 0;
}

/**
* Check if the current statistic entry is empty. This means
* that the statistic entry can be easily deleted if no activity
* occured for a while.
*
* @return bool
*/
public function shouldHaveTracesRemoved(): bool
{
return $this->currentConnectionsCount === 0 && $this->peakConnectionsCount === 0;
}

/**
* Transform the statistic to array.
*
Expand Down
51 changes: 49 additions & 2 deletions tests/StatisticsStoreTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,21 @@ public function test_store_statistics_on_public_channel()
$this->assertEquals('2', $records[0]['peak_connections_count']);
$this->assertEquals('2', $records[0]['websocket_messages_count']);
$this->assertEquals('0', $records[0]['api_messages_count']);

$this->pusherServer->onClose($rick);
$this->pusherServer->onClose($morty);

$this->statisticsCollector->save();

$this->assertCount(2, $records = $this->statisticsStore->getRecords());

$this->assertEquals('2', $records[1]['peak_connections_count']);

$this->statisticsCollector->save();

// The last one should not generate any more records
// since the current state is empty.
$this->assertCount(2, $records = $this->statisticsStore->getRecords());
}

public function test_store_statistics_on_private_channel()
Expand All @@ -30,19 +45,51 @@ public function test_store_statistics_on_private_channel()
$this->assertEquals('2', $records[0]['peak_connections_count']);
$this->assertEquals('2', $records[0]['websocket_messages_count']);
$this->assertEquals('0', $records[0]['api_messages_count']);

$this->pusherServer->onClose($rick);
$this->pusherServer->onClose($morty);

$this->statisticsCollector->save();

$this->assertCount(2, $records = $this->statisticsStore->getRecords());

$this->assertEquals('2', $records[1]['peak_connections_count']);

$this->statisticsCollector->save();

// The last one should not generate any more records
// since the current state is empty.
$this->assertCount(2, $records = $this->statisticsStore->getRecords());
}

public function test_store_statistics_on_presence_channel()
{
$rick = $this->newPresenceConnection('presence-channel', ['user_id' => 1]);
$morty = $this->newPresenceConnection('presence-channel', ['user_id' => 2]);
$pickleRick = $this->newPresenceConnection('presence-channel', ['user_id' => 1]);

$this->statisticsCollector->save();

$this->assertCount(1, $records = $this->statisticsStore->getRecords());

$this->assertEquals('2', $records[0]['peak_connections_count']);
$this->assertEquals('2', $records[0]['websocket_messages_count']);
$this->assertEquals('3', $records[0]['peak_connections_count']);
$this->assertEquals('3', $records[0]['websocket_messages_count']);
$this->assertEquals('0', $records[0]['api_messages_count']);

$this->pusherServer->onClose($rick);
$this->pusherServer->onClose($morty);
$this->pusherServer->onClose($pickleRick);

$this->statisticsCollector->save();

$this->assertCount(2, $records = $this->statisticsStore->getRecords());

$this->assertEquals('3', $records[1]['peak_connections_count']);

$this->statisticsCollector->save();

// The last one should not generate any more records
// since the current state is empty.
$this->assertCount(2, $records = $this->statisticsStore->getRecords());
}
}