From 91adcbf3f0f2dca8f18ae1d14b9a3991ea1815db Mon Sep 17 00:00:00 2001 From: Pulse Monitor Date: Thu, 28 Aug 2025 17:32:29 +0000 Subject: [PATCH] fix: address intermittent configuration display issue (#372) - Increased rate limits for configuration GET endpoints to prevent 429 errors - Added automatic retry logic for rate-limited requests with exponential backoff - Added small delays between initial API calls to prevent burst requests - Configuration read endpoints now use PublicEndpoints limit (1000/min vs 500/min) This should resolve the issue where the configuration page sometimes shows no information and prompts for system setup even when it's already configured. --- .../src/components/Settings/Settings.tsx | 9 ++++++++- frontend-modern/src/utils/apiClient.ts | 18 ++++++++++++++++-- internal/api/rate_limit_config.go | 7 +++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/frontend-modern/src/components/Settings/Settings.tsx b/frontend-modern/src/components/Settings/Settings.tsx index 9ca28f787..1861b644c 100644 --- a/frontend-modern/src/components/Settings/Settings.tsx +++ b/frontend-modern/src/components/Settings/Settings.tsx @@ -344,12 +344,19 @@ const Settings: Component = () => { }); try { - // Load security status + // Load data with small delays to prevent rate limit bursts + // Load security status first as it's lightweight await loadSecurityStatus(); + // Small delay to prevent burst + await new Promise(resolve => setTimeout(resolve, 50)); + // Load nodes await loadNodes(); + // Another small delay + await new Promise(resolve => setTimeout(resolve, 50)); + // Load discovered nodes await loadDiscoveredNodes(); diff --git a/frontend-modern/src/utils/apiClient.ts b/frontend-modern/src/utils/apiClient.ts index 7f28fc41b..d19211b27 100644 --- a/frontend-modern/src/utils/apiClient.ts +++ b/frontend-modern/src/utils/apiClient.ts @@ -147,9 +147,23 @@ class ApiClient { } } - // Handle rate limiting + // Handle rate limiting with automatic retry if (response.status === 429) { - console.error('Rate limit exceeded - please wait before retrying'); + const retryAfter = response.headers.get('Retry-After'); + const waitTime = retryAfter ? parseInt(retryAfter) * 1000 : 2000; // Default 2 seconds + + console.warn(`Rate limit hit, retrying after ${waitTime}ms`); + + // Wait and retry once + await new Promise(resolve => setTimeout(resolve, waitTime)); + + const retryResponse = await fetch(url, { + ...fetchOptions, + headers: finalHeaders, + credentials: 'include' + }); + + return retryResponse; } return response; diff --git a/internal/api/rate_limit_config.go b/internal/api/rate_limit_config.go index 8a3b813f2..b9573bde6 100644 --- a/internal/api/rate_limit_config.go +++ b/internal/api/rate_limit_config.go @@ -85,6 +85,13 @@ func GetRateLimiterForEndpoint(path string, method string) *RateLimiter { return globalRateLimitConfig.ConfigEndpoints } + // Configuration read endpoints get higher limits to prevent UI issues + if method == "GET" && (strings.Contains(path, "/api/config/") || + strings.Contains(path, "/api/discover") || + strings.Contains(path, "/api/security/status")) { + return globalRateLimitConfig.PublicEndpoints // Use higher limit for reads + } + // Update endpoints if strings.Contains(path, "/api/updates") { return globalRateLimitConfig.UpdateEndpoints