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

[fix] Memory Leaks #475

Merged
merged 6 commits into from
Aug 21, 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
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