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

Commit de7e358

Browse files
authored
Merge pull request #633 from beyondcode/fix/fix-stale-data
[fix] Fix stale data
2 parents cbe4378 + a99b5d0 commit de7e358

File tree

5 files changed

+96
-4
lines changed

5 files changed

+96
-4
lines changed

src/Contracts/StatisticsCollector.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,13 @@ public function getStatistics(): PromiseInterface;
6666
* @return PromiseInterface[\BeyondCode\LaravelWebSockets\Statistics\Statistic|null]
6767
*/
6868
public function getAppStatistics($appId): PromiseInterface;
69+
70+
/**
71+
* Remove all app traces from the database if no connections have been set
72+
* in the meanwhile since last save.
73+
*
74+
* @param string|int $appId
75+
* @return void
76+
*/
77+
public function resetAppTraces($appId);
6978
}

src/Statistics/Collectors/MemoryCollector.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,12 @@ public function save()
9696
continue;
9797
}
9898

99+
if ($statistic->shouldHaveTracesRemoved()) {
100+
$this->resetAppTraces($appId);
101+
102+
continue;
103+
}
104+
99105
$this->createRecord($statistic, $appId);
100106

101107
$this->channelManager
@@ -142,6 +148,18 @@ public function getAppStatistics($appId): PromiseInterface
142148
);
143149
}
144150

151+
/**
152+
* Remove all app traces from the database if no connections have been set
153+
* in the meanwhile since last save.
154+
*
155+
* @param string|int $appId
156+
* @return void
157+
*/
158+
public function resetAppTraces($appId)
159+
{
160+
unset($this->statistics[$appId]);
161+
}
162+
145163
/**
146164
* Find or create a defined statistic for an app.
147165
*

src/Statistics/Collectors/RedisCollector.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,10 @@ public function save()
170170
$appId, Helpers::redisListToArray($list)
171171
);
172172

173+
if ($statistic->shouldHaveTracesRemoved()) {
174+
return $this->resetAppTraces($appId);
175+
}
176+
173177
$this->createRecord($statistic, $appId);
174178

175179
$this->channelManager
@@ -265,7 +269,7 @@ public function resetStatistics($appId, int $currentConnectionCount)
265269
->getPublishClient()
266270
->hset(
267271
$this->channelManager->getRedisKey($appId, null, ['stats']),
268-
'peak_connections_count', $currentConnectionCount
272+
'peak_connections_count', max(0, $currentConnectionCount)
269273
);
270274

271275
$this->channelManager
@@ -292,6 +296,8 @@ public function resetStatistics($appId, int $currentConnectionCount)
292296
*/
293297
public function resetAppTraces($appId)
294298
{
299+
parent::resetAppTraces($appId);
300+
295301
$this->channelManager
296302
->getPublishClient()
297303
->hdel(

src/Statistics/Statistic.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,11 +178,23 @@ public function apiMessage()
178178
public function reset(int $currentConnectionsCount)
179179
{
180180
$this->currentConnectionsCount = $currentConnectionsCount;
181-
$this->peakConnectionsCount = $currentConnectionsCount;
181+
$this->peakConnectionsCount = max(0, $currentConnectionsCount);
182182
$this->webSocketMessagesCount = 0;
183183
$this->apiMessagesCount = 0;
184184
}
185185

186+
/**
187+
* Check if the current statistic entry is empty. This means
188+
* that the statistic entry can be easily deleted if no activity
189+
* occured for a while.
190+
*
191+
* @return bool
192+
*/
193+
public function shouldHaveTracesRemoved(): bool
194+
{
195+
return $this->currentConnectionsCount === 0 && $this->peakConnectionsCount === 0;
196+
}
197+
186198
/**
187199
* Transform the statistic to array.
188200
*

tests/StatisticsStoreTest.php

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,21 @@ public function test_store_statistics_on_public_channel()
1616
$this->assertEquals('2', $records[0]['peak_connections_count']);
1717
$this->assertEquals('2', $records[0]['websocket_messages_count']);
1818
$this->assertEquals('0', $records[0]['api_messages_count']);
19+
20+
$this->pusherServer->onClose($rick);
21+
$this->pusherServer->onClose($morty);
22+
23+
$this->statisticsCollector->save();
24+
25+
$this->assertCount(2, $records = $this->statisticsStore->getRecords());
26+
27+
$this->assertEquals('2', $records[1]['peak_connections_count']);
28+
29+
$this->statisticsCollector->save();
30+
31+
// The last one should not generate any more records
32+
// since the current state is empty.
33+
$this->assertCount(2, $records = $this->statisticsStore->getRecords());
1934
}
2035

2136
public function test_store_statistics_on_private_channel()
@@ -30,19 +45,51 @@ public function test_store_statistics_on_private_channel()
3045
$this->assertEquals('2', $records[0]['peak_connections_count']);
3146
$this->assertEquals('2', $records[0]['websocket_messages_count']);
3247
$this->assertEquals('0', $records[0]['api_messages_count']);
48+
49+
$this->pusherServer->onClose($rick);
50+
$this->pusherServer->onClose($morty);
51+
52+
$this->statisticsCollector->save();
53+
54+
$this->assertCount(2, $records = $this->statisticsStore->getRecords());
55+
56+
$this->assertEquals('2', $records[1]['peak_connections_count']);
57+
58+
$this->statisticsCollector->save();
59+
60+
// The last one should not generate any more records
61+
// since the current state is empty.
62+
$this->assertCount(2, $records = $this->statisticsStore->getRecords());
3363
}
3464

3565
public function test_store_statistics_on_presence_channel()
3666
{
3767
$rick = $this->newPresenceConnection('presence-channel', ['user_id' => 1]);
3868
$morty = $this->newPresenceConnection('presence-channel', ['user_id' => 2]);
69+
$pickleRick = $this->newPresenceConnection('presence-channel', ['user_id' => 1]);
3970

4071
$this->statisticsCollector->save();
4172

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

44-
$this->assertEquals('2', $records[0]['peak_connections_count']);
45-
$this->assertEquals('2', $records[0]['websocket_messages_count']);
75+
$this->assertEquals('3', $records[0]['peak_connections_count']);
76+
$this->assertEquals('3', $records[0]['websocket_messages_count']);
4677
$this->assertEquals('0', $records[0]['api_messages_count']);
78+
79+
$this->pusherServer->onClose($rick);
80+
$this->pusherServer->onClose($morty);
81+
$this->pusherServer->onClose($pickleRick);
82+
83+
$this->statisticsCollector->save();
84+
85+
$this->assertCount(2, $records = $this->statisticsStore->getRecords());
86+
87+
$this->assertEquals('3', $records[1]['peak_connections_count']);
88+
89+
$this->statisticsCollector->save();
90+
91+
// The last one should not generate any more records
92+
// since the current state is empty.
93+
$this->assertCount(2, $records = $this->statisticsStore->getRecords());
4794
}
4895
}

0 commit comments

Comments
 (0)