Refactor Node Stats

They have been problematic from day one... no need to make them a scheduled job
This commit is contained in:
notCharles 2025-03-21 18:57:05 -04:00
parent 23f39acd4e
commit a3d1da3e6a
4 changed files with 46 additions and 66 deletions

View File

@ -7,7 +7,6 @@ use App\Console\Commands\Maintenance\CleanServiceBackupFilesCommand;
use App\Console\Commands\Maintenance\PruneImagesCommand; use App\Console\Commands\Maintenance\PruneImagesCommand;
use App\Console\Commands\Maintenance\PruneOrphanedBackupsCommand; use App\Console\Commands\Maintenance\PruneOrphanedBackupsCommand;
use App\Console\Commands\Schedule\ProcessRunnableCommand; use App\Console\Commands\Schedule\ProcessRunnableCommand;
use App\Jobs\NodeStatistics;
use App\Models\ActivityLog; use App\Models\ActivityLog;
use App\Models\Webhook; use App\Models\Webhook;
use Illuminate\Console\Scheduling\Schedule; use Illuminate\Console\Scheduling\Schedule;
@ -41,8 +40,6 @@ class Kernel extends ConsoleKernel
$schedule->command(PruneImagesCommand::class)->daily(); $schedule->command(PruneImagesCommand::class)->daily();
$schedule->command(CheckEggUpdatesCommand::class)->hourly(); $schedule->command(CheckEggUpdatesCommand::class)->hourly();
$schedule->job(new NodeStatistics())->everyFiveSeconds()->withoutOverlapping();
if (config('backups.prune_age')) { if (config('backups.prune_age')) {
// Every 30 minutes, run the backup pruning command so that any abandoned backups can be deleted. // Every 30 minutes, run the backup pruning command so that any abandoned backups can be deleted.
$schedule->command(PruneOrphanedBackupsCommand::class)->everyThirtyMinutes(); $schedule->command(PruneOrphanedBackupsCommand::class)->everyThirtyMinutes();

View File

@ -3,35 +3,41 @@
namespace App\Filament\Admin\Resources\NodeResource\Widgets; namespace App\Filament\Admin\Resources\NodeResource\Widgets;
use App\Models\Node; use App\Models\Node;
use Carbon\Carbon;
use Filament\Support\RawJs; use Filament\Support\RawJs;
use Filament\Widgets\ChartWidget; use Filament\Widgets\ChartWidget;
use Illuminate\Support\Number; use Illuminate\Support\Number;
class NodeCpuChart extends ChartWidget class NodeCpuChart extends ChartWidget
{ {
protected static ?string $pollingInterval = '5s'; protected static ?string $pollingInterval = '1s';
protected static ?string $maxHeight = '300px'; protected static ?string $maxHeight = '300px';
public Node $node; public Node $node;
/**
* @var array<int, array{cpu: string, timestamp: string}>
*/
protected array $cpuHistory = [];
protected function getData(): array protected function getData(): array
{ {
$threads = $this->node->systemInformation()['cpu_count'] ?? 0; $data = $this->node->statistics();
$threads = $this->node->systemInformation()['cpu_count'];
$cpu = collect(cache()->get("nodes.{$this->node->id}.cpu_percent")) $this->cpuHistory = session()->get('cpuHistory', []);
->slice(-10) $this->cpuHistory[] = [
->map(fn ($value, $key) => [ 'cpu' => Number::format($data['cpu_percent'] * $threads, maxPrecision: 2),
'cpu' => Number::format($value * $threads, maxPrecision: 2), 'timestamp' => now(auth()->user()->timezone ?? 'UTC')->format('H:i:s'),
'timestamp' => Carbon::createFromTimestamp($key, auth()->user()->timezone ?? 'UTC')->format('H:i:s'), ];
])
->all(); $this->cpuHistory = array_slice($this->cpuHistory, -60);
session()->put('cpuHistory', $this->cpuHistory);
return [ return [
'datasets' => [ 'datasets' => [
[ [
'data' => array_column($cpu, 'cpu'), 'data' => array_column($this->cpuHistory, 'cpu'),
'backgroundColor' => [ 'backgroundColor' => [
'rgba(96, 165, 250, 0.3)', 'rgba(96, 165, 250, 0.3)',
], ],
@ -39,7 +45,7 @@ class NodeCpuChart extends ChartWidget
'fill' => true, 'fill' => true,
], ],
], ],
'labels' => array_column($cpu, 'timestamp'), 'labels' => array_column($this->cpuHistory, 'timestamp'),
'locale' => auth()->user()->language ?? 'en', 'locale' => auth()->user()->language ?? 'en',
]; ];
} }
@ -69,9 +75,10 @@ class NodeCpuChart extends ChartWidget
public function getHeading(): string public function getHeading(): string
{ {
$threads = $this->node->systemInformation()['cpu_count'] ?? 0; $threads = $this->node->systemInformation()['cpu_count'];
$data = array_slice(end($this->cpuHistory), -60);
$cpu = Number::format(collect(cache()->get("nodes.{$this->node->id}.cpu_percent"))->last() * $threads, maxPrecision: 2, locale: auth()->user()->language); $cpu = Number::format($data['cpu'], maxPrecision: 2, locale: auth()->user()->language);
$max = Number::format($threads * 100, locale: auth()->user()->language); $max = Number::format($threads * 100, locale: auth()->user()->language);
return trans('admin/node.cpu_chart', ['cpu' => $cpu, 'max' => $max]); return trans('admin/node.cpu_chart', ['cpu' => $cpu, 'max' => $max]);

View File

@ -3,32 +3,43 @@
namespace App\Filament\Admin\Resources\NodeResource\Widgets; namespace App\Filament\Admin\Resources\NodeResource\Widgets;
use App\Models\Node; use App\Models\Node;
use Carbon\Carbon;
use Filament\Support\RawJs; use Filament\Support\RawJs;
use Filament\Widgets\ChartWidget; use Filament\Widgets\ChartWidget;
use Illuminate\Support\Number; use Illuminate\Support\Number;
class NodeMemoryChart extends ChartWidget class NodeMemoryChart extends ChartWidget
{ {
protected static ?string $pollingInterval = '5s'; protected static ?string $pollingInterval = '1s';
protected static ?string $maxHeight = '300px'; protected static ?string $maxHeight = '300px';
public Node $node; public Node $node;
/**
* @var array<int, array{memory: string, timestamp: string}>
*/
protected array $memoryHistory = [];
protected function getData(): array protected function getData(): array
{ {
$memUsed = collect(cache()->get("nodes.{$this->node->id}.memory_used"))->slice(-10) $data = $this->node->statistics();
->map(fn ($value, $key) => [ $value = $data['memory_used'];
'memory' => Number::format(config('panel.use_binary_prefix') ? $value / 1024 / 1024 / 1024 : $value / 1000 / 1000 / 1000, maxPrecision: 2),
'timestamp' => Carbon::createFromTimestamp($key, auth()->user()->timezone ?? 'UTC')->format('H:i:s'), $this->memoryHistory = session()->get('memoryHistory', []);
]) $this->memoryHistory[] = [
->all(); 'memory' => Number::format(config('panel.use_binary_prefix')
? $value / 1024 / 1024 / 1024
: $value / 1000 / 1000 / 1000, maxPrecision: 2),
'timestamp' => now(auth()->user()->timezone ?? 'UTC')->format('H:i:s'),
];
$this->memoryHistory = array_slice($this->memoryHistory, -60);
session()->put('memoryHistory', $this->memoryHistory);
return [ return [
'datasets' => [ 'datasets' => [
[ [
'data' => array_column($memUsed, 'memory'), 'data' => array_column($this->memoryHistory, 'memory'),
'backgroundColor' => [ 'backgroundColor' => [
'rgba(96, 165, 250, 0.3)', 'rgba(96, 165, 250, 0.3)',
], ],
@ -36,7 +47,7 @@ class NodeMemoryChart extends ChartWidget
'fill' => true, 'fill' => true,
], ],
], ],
'labels' => array_column($memUsed, 'timestamp'), 'labels' => array_column($this->memoryHistory, 'timestamp'),
'locale' => auth()->user()->language ?? 'en', 'locale' => auth()->user()->language ?? 'en',
]; ];
} }
@ -66,12 +77,12 @@ class NodeMemoryChart extends ChartWidget
public function getHeading(): string public function getHeading(): string
{ {
$latestMemoryUsed = collect(cache()->get("nodes.{$this->node->id}.memory_used"))->last(); $latestMemoryUsed = array_slice(end($this->memoryHistory), -60);
$totalMemory = collect(cache()->get("nodes.{$this->node->id}.memory_total"))->last(); $totalMemory = $this->node->statistics()['memory_total'];
$used = config('panel.use_binary_prefix') $used = config('panel.use_binary_prefix')
? Number::format($latestMemoryUsed / 1024 / 1024 / 1024, maxPrecision: 2, locale: auth()->user()->language) .' GiB' ? Number::format($latestMemoryUsed['memory'], maxPrecision: 2, locale: auth()->user()->language) .' GiB'
: Number::format($latestMemoryUsed / 1000 / 1000 / 1000, maxPrecision: 2, locale: auth()->user()->language) . ' GB'; : Number::format($latestMemoryUsed['memory'], maxPrecision: 2, locale: auth()->user()->language) . ' GB';
$total = config('panel.use_binary_prefix') $total = config('panel.use_binary_prefix')
? Number::format($totalMemory / 1024 / 1024 / 1024, maxPrecision: 2, locale: auth()->user()->language) .' GiB' ? Number::format($totalMemory / 1024 / 1024 / 1024, maxPrecision: 2, locale: auth()->user()->language) .' GiB'

View File

@ -1,35 +0,0 @@
<?php
namespace App\Jobs;
use App\Models\Node;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class NodeStatistics implements ShouldBeUnique, ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function handle(): void
{
foreach (Node::all() as $node) {
$stats = $node->statistics();
$timestamp = now()->getTimestamp();
foreach ($stats as $key => $value) {
$cacheKey = "nodes.{$node->id}.$key";
$data = cache()->get($cacheKey, []);
// Add current timestamp and value to the data array
$data[$timestamp] = $value;
// Update the cache with the new data, expires in 1 minute
cache()->put($cacheKey, $data, now()->addMinute());
}
}
}
}