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

Commit

Permalink
Merge pull request #475 from beyondcode/fix/memory-leaks
Browse files Browse the repository at this point in the history
[fix] Memory Leaks
  • Loading branch information
rennokki authored Aug 21, 2020
2 parents b4c7f34 + 70ce44e commit a08eee6
Show file tree
Hide file tree
Showing 15 changed files with 137 additions and 323 deletions.
31 changes: 0 additions & 31 deletions config/websockets.php
Original file line number Diff line number Diff line change
Expand Up @@ -239,37 +239,6 @@

'delete_statistics_older_than_days' => 60,

/*
|--------------------------------------------------------------------------
| DNS Lookup
|--------------------------------------------------------------------------
|
| Use an DNS resolver to make the requests to the statistics logger
| default is to resolve everything to 127.0.0.1.
|
*/

'perform_dns_lookup' => false,

/*
|--------------------------------------------------------------------------
| DNS Lookup TLS Settings
|--------------------------------------------------------------------------
|
| You can configure the DNS Lookup Connector the TLS settings.
| Check the available options here:
| https://github.com/reactphp/socket/blob/master/src/Connector.php#L29
|
*/

'tls' => [

'verify_peer' => env('APP_ENV') === 'production',

'verify_peer_name' => env('APP_ENV') === 'production',

],

],

];
74 changes: 57 additions & 17 deletions resources/views/dashboard.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,29 @@ class="rounded-full px-3 py-2 text-white focus:outline-none"
v-if="connected && app.statisticsEnabled"
class="w-full my-6 px-6"
>
<div class="font-semibold uppercase text-gray-700">
Live statistics
</div>
<div class="flex justify-between items-center">
<span class="font-semibold uppercase text-gray-700">
Live statistics
</span>

<div class="space-x-3 flex items-center">
<div>
<input
type="checkbox"
v-model="autoRefresh"
class="mr-2"
/>
Refresh automatically
</div>

<button
@click="loadChart"
class="rounded-full bg-blue-500 hover:bg-blue-600 focus:outline-none text-white px-3 py-1"
>
Refresh
</button>
</div>
</div>

<div
id="statisticsChart"
Expand Down Expand Up @@ -222,6 +242,9 @@ class="rounded-full px-3 py-1 inline-block text-sm"
connected: false,
connecting: false,
sendingEvent: false,
autoRefresh: true,
refreshInterval: {{ $refreshInterval }},
refreshTicker: null,
chart: null,
pusher: null,
app: null,
Expand All @@ -236,6 +259,19 @@ class="rounded-full px-3 py-1 inline-block text-sm"
mounted () {
this.app = this.apps[0] || null;
},
destroyed () {
if (this.refreshTicker) {
this.clearRefreshInterval();
}
},
watch: {
connected (newVal) {
newVal ? this.startRefreshInterval() : this.clearRefreshInterval();
},
autoRefresh (newVal) {
newVal ? this.startRefreshInterval() : this.clearRefreshInterval();
},
},
methods: {
connect () {
this.connecting = true;
Expand Down Expand Up @@ -274,12 +310,14 @@ class="rounded-full px-3 py-1 inline-block text-sm"
this.connected = false;
this.connecting = false;
this.logs = [];
this.chart = null;
});
this.pusher.connection.bind('error', event => {
if (event.error.data.code === 4100) {
this.connected = false;
this.logs = [];
this.chart = null;
throw new Error("Over capacity");
}
Expand All @@ -288,12 +326,12 @@ class="rounded-full px-3 py-1 inline-block text-sm"
});
this.subscribeToAllChannels();
this.subscribeToStatistics();
},
disconnect () {
this.pusher.disconnect();
this.connecting = false;
this.chart = null;
},
loadChart () {
Expand Down Expand Up @@ -333,7 +371,10 @@ class="rounded-full px-3 py-1 inline-block text-sm"
autosize: true,
};
this.chart = Plotly.newPlot('statisticsChart', chartData, layout);
this.chart = this.chart
? Plotly.react('statisticsChart', chartData, layout)
: Plotly.newPlot('statisticsChart', chartData, layout);
});
},
Expand All @@ -348,18 +389,6 @@ class="rounded-full px-3 py-1 inline-block text-sm"
});
},
subscribeToStatistics () {
this.pusher.subscribe('{{ $logPrefix }}statistics')
.bind('statistics-updated', (data) => {
var update = {
x: [[data.time], [data.time], [data.time]],
y: [[data.peak_connection_count], [data.websocket_message_count], [data.api_message_count]],
};
Plotly.extendTraces('statisticsChart', update, [0, 1, 2]);
});
},
sendEvent () {
if (! this.sendingEvent) {
this.sendingEvent = true;
Expand Down Expand Up @@ -415,6 +444,17 @@ class="rounded-full px-3 py-1 inline-block text-sm"
return 'bg-gray-700 text-white';
},
startRefreshInterval () {
this.refreshTicker = setInterval(function () {
this.loadChart();
}.bind(this), this.refreshInterval * 1000);
},
stopRefreshInterval () {
clearInterval(this.refreshTicker);
this.refreshTicker = null;
},
},
});
</script>
Expand Down
39 changes: 3 additions & 36 deletions src/Console/StartWebSocketServer.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,12 @@
use BeyondCode\LaravelWebSockets\Server\Logger\HttpLogger;
use BeyondCode\LaravelWebSockets\Server\Logger\WebsocketsLogger;
use BeyondCode\LaravelWebSockets\Server\WebSocketServerFactory;
use BeyondCode\LaravelWebSockets\Statistics\DnsResolver;
use BeyondCode\LaravelWebSockets\Statistics\Drivers\StatisticsDriver;
use BeyondCode\LaravelWebSockets\Statistics\Logger\StatisticsLogger as StatisticsLoggerInterface;
use BeyondCode\LaravelWebSockets\WebSockets\Channels\ChannelManager;
use Clue\React\Buzz\Browser;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Cache;
use React\Dns\Config\Config as DnsConfig;
use React\Dns\Resolver\Factory as DnsFactory;
use React\Dns\Resolver\ResolverInterface;
use React\EventLoop\Factory as LoopFactory;
use React\Socket\Connector;

class StartWebSocketServer extends Command
{
Expand Down Expand Up @@ -103,19 +98,12 @@ public function handle()
*/
protected function configureStatisticsLogger()
{
$connector = new Connector($this->loop, [
'dns' => $this->getDnsResolver(),
'tls' => config('websockets.statistics.tls'),
]);

$browser = new Browser($this->loop, $connector);

$this->laravel->singleton(StatisticsLoggerInterface::class, function () use ($browser) {
$this->laravel->singleton(StatisticsLoggerInterface::class, function () {
$class = config('websockets.statistics.logger', \BeyondCode\LaravelWebSockets\Statistics\Logger\MemoryStatisticsLogger::class);

return new $class(
$this->laravel->make(ChannelManager::class),
$browser
$this->laravel->make(StatisticsDriver::class)
);
});

Expand Down Expand Up @@ -273,27 +261,6 @@ protected function buildServer()
->createServer();
}

/**
* Create a DNS resolver for the stats manager.
*
* @return \React\Dns\Resolver\ResolverInterface
*/
protected function getDnsResolver(): ResolverInterface
{
if (! config('websockets.statistics.perform_dns_lookup')) {
return new DnsResolver;
}

$dnsConfig = DnsConfig::loadSystemConfigBlocking();

return (new DnsFactory)->createCached(
$dnsConfig->nameservers
? reset($dnsConfig->nameservers)
: '1.1.1.1',
$this->loop
);
}

/**
* Get the last time the server restarted.
*
Expand Down
38 changes: 7 additions & 31 deletions src/Dashboard/Http/Controllers/DashboardApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,21 @@

namespace BeyondCode\LaravelWebSockets\Dashboard\Http\Controllers;

use BeyondCode\LaravelWebSockets\Statistics\Drivers\StatisticsDriver;
use Illuminate\Http\Request;

class DashboardApiController
{
/**
* Get statistics for an app ID.
*
* @param \Illuminate\Http\Request $request
* @param \BeyondCode\LaravelWebSockets\Statistics\Drivers\StatisticsDriver $driver
* @param mixed $appId
* @return \Illuminate\Http\Response
*/
public function getStatistics($appId)
public function getStatistics(Request $request, StatisticsDriver $driver, $appId)
{
$model = config('websockets.statistics.model');

$statistics = $model::where('app_id', $appId)
->latest()
->limit(120)
->get();

$statisticData = $statistics->map(function ($statistic) {
return [
'timestamp' => (string) $statistic->created_at,
'peak_connection_count' => $statistic->peak_connection_count,
'websocket_message_count' => $statistic->websocket_message_count,
'api_message_count' => $statistic->api_message_count,
];
})->reverse();

return [
'peak_connections' => [
'x' => $statisticData->pluck('timestamp'),
'y' => $statisticData->pluck('peak_connection_count'),
],
'websocket_message_count' => [
'x' => $statisticData->pluck('timestamp'),
'y' => $statisticData->pluck('websocket_message_count'),
],
'api_message_count' => [
'x' => $statisticData->pluck('timestamp'),
'y' => $statisticData->pluck('api_message_count'),
],
];
return $driver::get($appId, $request);
}
}
1 change: 1 addition & 0 deletions src/Dashboard/Http/Controllers/ShowDashboard.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public function __invoke(Request $request, AppManager $apps)
'port' => config('websockets.dashboard.port', 6001),
'channels' => DashboardLogger::$channels,
'logPrefix' => DashboardLogger::LOG_CHANNEL_PREFIX,
'refreshInterval' => config('websockets.statistics.interval_in_seconds'),
]);
}
}
41 changes: 41 additions & 0 deletions src/Statistics/Drivers/DatabaseDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace BeyondCode\LaravelWebSockets\Statistics\Drivers;

use Carbon\Carbon;
use Illuminate\Http\Request;

class DatabaseDriver implements StatisticsDriver
{
Expand Down Expand Up @@ -87,6 +88,46 @@ public static function create(array $data): StatisticsDriver
return new static($class::create($data));
}

/**
* Get the records to show to the dashboard.
*
* @param mixed $appId
* @param \Illuminate\Http\Request $request
* @return array
*/
public static function get($appId, Request $request): array
{
$class = config('websockets.statistics.database.model');

$statistics = $class::whereAppId($appId)
->latest()
->limit(120)
->get()
->map(function ($statistic) {
return [
'timestamp' => (string) $statistic->created_at,
'peak_connection_count' => $statistic->peak_connection_count,
'websocket_message_count' => $statistic->websocket_message_count,
'api_message_count' => $statistic->api_message_count,
];
})->reverse();

return [
'peak_connections' => [
'x' => $statistics->pluck('timestamp'),
'y' => $statistics->pluck('peak_connection_count'),
],
'websocket_message_count' => [
'x' => $statistics->pluck('timestamp'),
'y' => $statistics->pluck('websocket_message_count'),
],
'api_message_count' => [
'x' => $statistics->pluck('timestamp'),
'y' => $statistics->pluck('api_message_count'),
],
];
}

/**
* Delete statistics from the store,
* optionally by app id, returning
Expand Down
11 changes: 11 additions & 0 deletions src/Statistics/Drivers/StatisticsDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace BeyondCode\LaravelWebSockets\Statistics\Drivers;

use Illuminate\Http\Request;

interface StatisticsDriver
{
/**
Expand Down Expand Up @@ -55,6 +57,15 @@ public function getApiMessageCount(): int;
*/
public static function create(array $data): StatisticsDriver;

/**
* Get the records to show to the dashboard.
*
* @param mixed $appId
* @param \Illuminate\Http\Request $request
* @return void
*/
public static function get($appId, Request $request);

/**
* Delete statistics from the store,
* optionally by app id, returning
Expand Down
Loading

0 comments on commit a08eee6

Please sign in to comment.