From f37084bdb2c07269be3ad1eecdcdeda8991d6777 Mon Sep 17 00:00:00 2001 From: "Joseph.Rawlings" Date: Mon, 8 Dec 2025 17:06:30 -0500 Subject: [PATCH] Enhance Proxmox statistics loading by dispatching individual chart events for improved reliability and parallel data fetching --- .../Servers/Proxmox/Livewire/Statistics.php | 38 ++++- .../Proxmox/views/statistics.blade.php | 144 +++++++++++++----- 2 files changed, 139 insertions(+), 43 deletions(-) diff --git a/extensions/Servers/Proxmox/Livewire/Statistics.php b/extensions/Servers/Proxmox/Livewire/Statistics.php index 0dc417f23..ae26441c0 100644 --- a/extensions/Servers/Proxmox/Livewire/Statistics.php +++ b/extensions/Servers/Proxmox/Livewire/Statistics.php @@ -141,19 +141,53 @@ class Statistics extends Component } // Preload graph data on mount to speed up initial display - // This runs in the background while the page is rendering - $this->dispatch('proxmox:stats'); + // Dispatch individual chart events for more reliable parallel loading + // Each chart loads independently so a failure in one doesn't block others + $this->dispatch('proxmox:stats:cpu'); + $this->dispatch('proxmox:stats:memory'); + $this->dispatch('proxmox:stats:network'); + $this->dispatch('proxmox:stats:disk'); } #[On('proxmox:stats')] public function stats(): void { + // Fetch each graph independently to prevent one failure from blocking others + // Each fetch is wrapped in its own try-catch in fetchGraphData() $this->fetchGraphData('cpu', $this->cpuTimeRange, $this->cpuAggregation); $this->fetchGraphData('memory', $this->memoryTimeRange, $this->memoryAggregation); $this->fetchGraphData('network', $this->networkTimeRange, $this->networkAggregation); $this->fetchGraphData('disk', $this->diskTimeRange, $this->diskAggregation); } + /** + * Fetch individual graph data - allows frontend to request specific graphs independently + * This improves reliability as each graph can be retried separately if it fails + */ + #[On('proxmox:stats:cpu')] + public function fetchCpuStats(): void + { + $this->fetchGraphData('cpu', $this->cpuTimeRange, $this->cpuAggregation); + } + + #[On('proxmox:stats:memory')] + public function fetchMemoryStats(): void + { + $this->fetchGraphData('memory', $this->memoryTimeRange, $this->memoryAggregation); + } + + #[On('proxmox:stats:network')] + public function fetchNetworkStats(): void + { + $this->fetchGraphData('network', $this->networkTimeRange, $this->networkAggregation); + } + + #[On('proxmox:stats:disk')] + public function fetchDiskStats(): void + { + $this->fetchGraphData('disk', $this->diskTimeRange, $this->diskAggregation); + } + /** * Explicit event handler for Network Analysis lazy loading. * diff --git a/extensions/Servers/Proxmox/views/statistics.blade.php b/extensions/Servers/Proxmox/views/statistics.blade.php index 84ee41137..1b1ec56c6 100644 --- a/extensions/Servers/Proxmox/views/statistics.blade.php +++ b/extensions/Servers/Proxmox/views/statistics.blade.php @@ -4466,48 +4466,97 @@ var networkChartHasData = false; var diskChartHasData = false; - var statsRetryAttempts = 0; - var maxStatsRetryAttempts = 5; + // Track individual retry attempts per chart for more reliable loading + var chartRetryAttempts = { + cpu: 0, + memory: 0, + network: 0, + disk: 0 + }; + var maxChartRetryAttempts = 5; + var chartRetryDelay = 1000; // 1 second between retries - function dispatchStatsWithRetry() { - function requestStatsOnce() { - statsRetryAttempts++; - - try { - console.log('Requesting Proxmox stats (attempt ' + statsRetryAttempts + ')'); - Livewire.dispatch('proxmox:stats'); - } catch (e) { - console.warn('Failed to dispatch Proxmox stats event:', e); - } - - // After a shorter delay, check if expected charts have received any data. - // Reduced from 3000ms to 800ms for faster loading - setTimeout(function () { - var allExpectedChartsHaveData = - (!cpuChartExpected || cpuChartHasData) && - (!memoryChartExpected || memoryChartHasData) && - (!networkChartExpected || networkChartHasData) && - (!diskChartExpected || diskChartHasData); - - if (allExpectedChartsHaveData) { - console.log('All expected charts have received data – stopping stats retries.'); - try { - window.dispatchEvent(new CustomEvent('proxmox-all-stats-loaded')); - } catch (e) {} - return; - } - - if (statsRetryAttempts < maxStatsRetryAttempts) { - requestStatsOnce(); - } else { - console.warn('Max stats retry attempts reached; some charts may not have data.'); - } - }, 800); + // Request individual chart data with retry logic + function requestChartData(chartType) { + if (chartRetryAttempts[chartType] >= maxChartRetryAttempts) { + console.warn('Max retry attempts reached for ' + chartType + ' chart'); + return; } - // Start the retry loop immediately - statsRetryAttempts = 0; - requestStatsOnce(); + chartRetryAttempts[chartType]++; + console.log('Requesting ' + chartType + ' chart data (attempt ' + chartRetryAttempts[chartType] + ')'); + + try { + // Dispatch individual chart event for more reliable loading + Livewire.dispatch('proxmox:stats:' + chartType); + } catch (e) { + console.warn('Failed to dispatch ' + chartType + ' stats event:', e); + } + } + + // Check if a specific chart needs data and retry if necessary + function checkAndRetryChart(chartType, chartHasData, chartExpected) { + if (!chartExpected || chartHasData) { + return; // Chart not needed or already has data + } + + setTimeout(function() { + // Re-check the current state (these vars are updated by event handlers) + var hasData = false; + switch(chartType) { + case 'cpu': hasData = cpuChartHasData; break; + case 'memory': hasData = memoryChartHasData; break; + case 'network': hasData = networkChartHasData; break; + case 'disk': hasData = diskChartHasData; break; + } + + if (!hasData && chartRetryAttempts[chartType] < maxChartRetryAttempts) { + requestChartData(chartType); + checkAndRetryChart(chartType, false, true); + } + }, chartRetryDelay); + } + + // Check if all charts have loaded and dispatch event + function checkAllChartsLoaded() { + var allExpectedChartsHaveData = + (!cpuChartExpected || cpuChartHasData) && + (!memoryChartExpected || memoryChartHasData) && + (!networkChartExpected || networkChartHasData) && + (!diskChartExpected || diskChartHasData); + + if (allExpectedChartsHaveData) { + console.log('All expected charts have received data.'); + try { + window.dispatchEvent(new CustomEvent('proxmox-all-stats-loaded')); + } catch (e) {} + } + } + + function dispatchStatsWithRetry() { + // Reset retry counters + chartRetryAttempts = { cpu: 0, memory: 0, network: 0, disk: 0 }; + + // Request all chart data in parallel using individual events + // This ensures each chart loads independently - if one fails, others still work + console.log('Requesting all Proxmox stats (parallel individual requests)'); + + if (cpuChartExpected) { + requestChartData('cpu'); + checkAndRetryChart('cpu', false, true); + } + if (memoryChartExpected) { + requestChartData('memory'); + checkAndRetryChart('memory', false, true); + } + if (networkChartExpected) { + requestChartData('network'); + checkAndRetryChart('network', false, true); + } + if (diskChartExpected) { + requestChartData('disk'); + checkAndRetryChart('disk', false, true); + } } function initializeCharts() { @@ -4588,10 +4637,15 @@ // Trigger initial stats request as soon as possible, before charts are ready // This allows backend to start fetching data in parallel with chart initialization + // Using individual chart events for more reliable loading if (typeof Livewire !== 'undefined') { setTimeout(function() { try { - Livewire.dispatch('proxmox:stats'); + // Dispatch all four chart requests in parallel for faster initial load + Livewire.dispatch('proxmox:stats:cpu'); + Livewire.dispatch('proxmox:stats:memory'); + Livewire.dispatch('proxmox:stats:network'); + Livewire.dispatch('proxmox:stats:disk'); } catch (e) { console.warn('Early stats dispatch failed:', e); } @@ -4630,6 +4684,7 @@ // Mark that this chart has successfully received data cpuChartHasData = true; + checkAllChartsLoaded(); } catch (e) { console.error('Error updating CPU chart:', e, eventData); } @@ -4661,6 +4716,7 @@ // Mark that this chart has successfully received data memoryChartHasData = true; + checkAllChartsLoaded(); } catch (e) { console.error('Error updating Memory chart:', e, eventData); } @@ -4700,6 +4756,7 @@ // Mark that this chart has successfully received data networkChartHasData = true; + checkAllChartsLoaded(); } catch (e) { console.error('Error updating Network chart:', e, eventData); } @@ -4739,6 +4796,7 @@ // Mark that this chart has successfully received data diskChartHasData = true; + checkAllChartsLoaded(); } catch (e) { console.error('Error updating Disk chart:', e, eventData); } @@ -4974,8 +5032,12 @@ initializeCharts(); }); + // Refresh stats periodically (every 2 minutes) using individual chart requests setInterval(function() { - Livewire.dispatch('proxmox:stats'); + Livewire.dispatch('proxmox:stats:cpu'); + Livewire.dispatch('proxmox:stats:memory'); + Livewire.dispatch('proxmox:stats:network'); + Livewire.dispatch('proxmox:stats:disk'); }, 120000); window.downloadCSV = window.downloadCSV || function(csvContent, filename) {