From 8a753ca9bab3e42b4121442a715e81aefe1e0336 Mon Sep 17 00:00:00 2001 From: triggermeelmo Date: Sun, 16 Nov 2025 23:53:58 +0100 Subject: [PATCH] =?UTF-8?q?Refresh=20Rate=20anpassbar,=20Container=C3=BCbe?= =?UTF-8?q?rsicht=20wird=20nicht=20mehr=20=C3=BCberschrieben?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Watcher/Controllers/HomeController.cs | 9 ++++-- Watcher/Controllers/MonitoringController.cs | 30 ++++++++++++++----- Watcher/Controllers/ServerController.cs | 13 ++++++-- Watcher/Program.cs | 16 +++++++++- Watcher/Services/ISystemStore.cs | 2 ++ Watcher/Services/SystemStore.cs | 2 ++ Watcher/ViewModels/DashboardViewModel.cs | 2 ++ Watcher/ViewModels/ServerDetailsViewModel.cs | 2 ++ Watcher/ViewModels/ServerOverviewViewModel.cs | 1 + Watcher/Views/Home/Index.cshtml | 4 +-- Watcher/Views/Server/Details.cshtml | 8 ++--- Watcher/Views/Server/_ServerCard.cshtml | 5 ++-- Watcher/Views/Server/overview.cshtml | 4 +-- Watcher/appsettings.json | 4 +++ docker-compose.yaml | 8 +++-- 15 files changed, 84 insertions(+), 26 deletions(-) diff --git a/Watcher/Controllers/HomeController.cs b/Watcher/Controllers/HomeController.cs index 07cdd11..f2ba7a9 100644 --- a/Watcher/Controllers/HomeController.cs +++ b/Watcher/Controllers/HomeController.cs @@ -21,12 +21,16 @@ namespace Watcher.Controllers // Daten der Backgroundchecks abrufen private IDashboardStore _DashboardStore; + // System Store für Konfigurationen + private ISystemStore _SystemStore; + // HomeController Constructor - public HomeController(AppDbContext context, ILogger logger, IDashboardStore dashboardStore) + public HomeController(AppDbContext context, ILogger logger, IDashboardStore dashboardStore, ISystemStore systemStore) { _context = context; _logger = logger; _DashboardStore = dashboardStore; + _SystemStore = systemStore; } @@ -59,7 +63,8 @@ namespace Watcher.Controllers .OrderBy(s => s.Name) .ToListAsync(), NetworkStatus = _DashboardStore.NetworkStatus, - DatabaseStatus = _DashboardStore.DatabaseStatus + DatabaseStatus = _DashboardStore.DatabaseStatus, + RefreshIntervalMilliseconds = _SystemStore.FrontendRefreshIntervalMilliseconds }; //ViewBag.NetworkConnection = _NetworkCheckStore.NetworkStatus; return View(viewModel); diff --git a/Watcher/Controllers/MonitoringController.cs b/Watcher/Controllers/MonitoringController.cs index faf6df9..429e2b6 100644 --- a/Watcher/Controllers/MonitoringController.cs +++ b/Watcher/Controllers/MonitoringController.cs @@ -280,9 +280,18 @@ public class MonitoringController : Controller foreach (Container c in newContainers) { // Überprüfen, ob ein übergebener Container bereits für den Host registriert ist - if (existingContainers.Contains(c)) + // Wichtig: Vergleich über ContainerId, nicht über Objektreferenz! + var existingContainer = existingContainers + .FirstOrDefault(ec => ec.ContainerId == c.ContainerId); + + if (existingContainer != null) { - _logger.LogInformation("Container with id " + c.ContainerId + " already exists."); + // Container existiert bereits, nur Daten aktualisieren falls sich etwas geändert hat + existingContainer.Name = c.Name; + existingContainer.Image = c.Image; + existingContainer.IsRunning = true; + + _logger.LogInformation("Container '{containerName}' (ID: {containerId}) already exists for Server {serverId}, updated.", c.Name, c.ContainerId, dto.Server_id); } // Container auf einen Host/Server registrieren else @@ -292,11 +301,11 @@ public class MonitoringController : Controller { _context.Containers.Add(c); await _context.SaveChangesAsync(); - _logger.LogInformation(c.Name + " added for Host " + c.ServerId); + _logger.LogInformation("Container '{containerName}' (ID: {containerId}) added for Server {serverId}", c.Name, c.ContainerId, c.ServerId); } catch (SqliteException e) { - _logger.LogError("Error writing new Containers to Database: " + e.Message); + _logger.LogError("Error writing new Container '{containerName}' to Database: {error}", c.Name, e.Message); } } } @@ -305,19 +314,26 @@ public class MonitoringController : Controller foreach (Container c in existingContainers) { // Abfrage, ob bereits vorhandener Container im Payload vorhanden war - if (!newContainers.Contains(c)) + // Wichtig: Vergleich über ContainerId, nicht über Objektreferenz! + var stillRunning = newContainers + .Any(nc => nc.ContainerId == c.ContainerId); + + if (!stillRunning) { // Container entfernen _context.Containers.Remove(c); await _context.SaveChangesAsync(); // Metrics für den Container entfernen - //Todo + //Todo - _logger.LogInformation("Container " + c.Name + " (" + c.Id + ") on Host-Id " + c.ServerId + " was successfully removed from the database."); + _logger.LogInformation("Container '{containerName}' (DB-ID: {id}, ContainerID: {containerId}) on Server {serverId} was removed from the database.", c.Name, c.Id, c.ContainerId, c.ServerId); } } + // Alle Änderungen in einem Batch speichern + await _context.SaveChangesAsync(); + return Ok(); } diff --git a/Watcher/Controllers/ServerController.cs b/Watcher/Controllers/ServerController.cs index ab41c01..720f3bd 100644 --- a/Watcher/Controllers/ServerController.cs +++ b/Watcher/Controllers/ServerController.cs @@ -4,6 +4,7 @@ using Microsoft.EntityFrameworkCore; using Watcher.Data; using Watcher.Models; using Watcher.ViewModels; +using Watcher.Services; [Authorize] [Route("[controller]")] @@ -13,11 +14,14 @@ public class ServerController : Controller private readonly ILogger _logger; + private readonly ISystemStore _systemStore; - public ServerController(AppDbContext context, ILogger logger) + + public ServerController(AppDbContext context, ILogger logger, ISystemStore systemStore) { _context = context; _logger = logger; + _systemStore = systemStore; } @@ -26,7 +30,8 @@ public class ServerController : Controller { var vm = new ServerOverviewViewModel { - Servers = await _context.Servers.OrderBy(s => s.Id).ToListAsync() + Servers = await _context.Servers.OrderBy(s => s.Id).ToListAsync(), + RefreshIntervalMilliseconds = _systemStore.FrontendRefreshIntervalMilliseconds }; return View(vm); @@ -159,7 +164,8 @@ public class ServerController : Controller CreatedAt = s.CreatedAt, IsOnline = s.IsOnline, LastSeen = s.LastSeen, - IsVerified = s.IsVerified + IsVerified = s.IsVerified, + RefreshIntervalMilliseconds = _systemStore.FrontendRefreshIntervalMilliseconds }; return View(vm); @@ -177,6 +183,7 @@ public class ServerController : Controller await _context.SaveChangesAsync(); } + ViewBag.RefreshIntervalMilliseconds = _systemStore.FrontendRefreshIntervalMilliseconds; return PartialView("_ServerCard", servers); } diff --git a/Watcher/Program.cs b/Watcher/Program.cs index d6fab21..7538ab6 100644 --- a/Watcher/Program.cs +++ b/Watcher/Program.cs @@ -34,10 +34,24 @@ builder.Services.AddHttpContextAccessor(); // Storage Singleton builder.Services.AddSingleton(); -builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); +// SystemStore mit Konfiguration initialisieren +builder.Services.AddSingleton(sp => +{ + var configuration = sp.GetRequiredService(); + var refreshIntervalSeconds = int.TryParse( + configuration["Frontend:RefreshIntervalSeconds"] + ?? Environment.GetEnvironmentVariable("FRONTEND_REFRESH_INTERVAL_SECONDS"), + out var seconds) ? seconds : 30; + + return new SystemStore + { + FrontendRefreshIntervalMilliseconds = refreshIntervalSeconds * 1000 + }; +}); + // Background Services builder.Services.AddHostedService(); builder.Services.AddHostedService(); diff --git a/Watcher/Services/ISystemStore.cs b/Watcher/Services/ISystemStore.cs index 1ee6d22..c2be934 100644 --- a/Watcher/Services/ISystemStore.cs +++ b/Watcher/Services/ISystemStore.cs @@ -6,4 +6,6 @@ public interface ISystemStore Double DatabaseSize { get; set; } + int FrontendRefreshIntervalMilliseconds { get; set; } + } \ No newline at end of file diff --git a/Watcher/Services/SystemStore.cs b/Watcher/Services/SystemStore.cs index 34fce64..5f67bbd 100644 --- a/Watcher/Services/SystemStore.cs +++ b/Watcher/Services/SystemStore.cs @@ -6,4 +6,6 @@ public class SystemStore: ISystemStore public Double DatabaseSize { get; set; } + public int FrontendRefreshIntervalMilliseconds { get; set; } + } \ No newline at end of file diff --git a/Watcher/ViewModels/DashboardViewModel.cs b/Watcher/ViewModels/DashboardViewModel.cs index 25c10e2..c05755e 100644 --- a/Watcher/ViewModels/DashboardViewModel.cs +++ b/Watcher/ViewModels/DashboardViewModel.cs @@ -17,5 +17,7 @@ namespace Watcher.ViewModels public String? NetworkStatus { get; set; } = "?"; public String? DatabaseStatus { get; set; } = "?"; + public int RefreshIntervalMilliseconds { get; set; } = 30000; + } } diff --git a/Watcher/ViewModels/ServerDetailsViewModel.cs b/Watcher/ViewModels/ServerDetailsViewModel.cs index 34047e9..efb7852 100644 --- a/Watcher/ViewModels/ServerDetailsViewModel.cs +++ b/Watcher/ViewModels/ServerDetailsViewModel.cs @@ -36,4 +36,6 @@ public class ServerDetailsViewModel public DateTime LastSeen { get; set; } public Boolean IsVerified { get; set; } = false; + + public int RefreshIntervalMilliseconds { get; set; } = 30000; } \ No newline at end of file diff --git a/Watcher/ViewModels/ServerOverviewViewModel.cs b/Watcher/ViewModels/ServerOverviewViewModel.cs index 72be054..bd58573 100644 --- a/Watcher/ViewModels/ServerOverviewViewModel.cs +++ b/Watcher/ViewModels/ServerOverviewViewModel.cs @@ -6,5 +6,6 @@ namespace Watcher.ViewModels public class ServerOverviewViewModel { public List Servers { get; set; } = new(); + public int RefreshIntervalMilliseconds { get; set; } = 30000; } } diff --git a/Watcher/Views/Home/Index.cshtml b/Watcher/Views/Home/Index.cshtml index f39e9c4..86610e2 100644 --- a/Watcher/Views/Home/Index.cshtml +++ b/Watcher/Views/Home/Index.cshtml @@ -31,8 +31,8 @@ } } - // Initial laden und dann alle 30 Sekunden + // Initial laden und dann mit konfiguriertem Intervall loadDashboardStats(); - setInterval(loadDashboardStats, 30000); + setInterval(loadDashboardStats, @Model.RefreshIntervalMilliseconds); } diff --git a/Watcher/Views/Server/Details.cshtml b/Watcher/Views/Server/Details.cshtml index ffb2aa1..4065689 100644 --- a/Watcher/Views/Server/Details.cshtml +++ b/Watcher/Views/Server/Details.cshtml @@ -480,10 +480,10 @@ loadRamData(); loadGpuData(); - // Alle 30 Sekunden aktualisieren - setInterval(loadCpuData, 30000); - setInterval(loadRamData, 30000); - setInterval(loadGpuData, 30000); + // Mit konfiguriertem Intervall aktualisieren + setInterval(loadCpuData, @Model.RefreshIntervalMilliseconds); + setInterval(loadRamData, @Model.RefreshIntervalMilliseconds); + setInterval(loadGpuData, @Model.RefreshIntervalMilliseconds); }); } \ No newline at end of file diff --git a/Watcher/Views/Server/_ServerCard.cshtml b/Watcher/Views/Server/_ServerCard.cshtml index 87ecf7d..bfe1d6a 100644 --- a/Watcher/Views/Server/_ServerCard.cshtml +++ b/Watcher/Views/Server/_ServerCard.cshtml @@ -163,7 +163,8 @@ } } - // Initial laden und alle 30 Sekunden aktualisieren + // Initial laden und mit konfiguriertem Intervall aktualisieren loadCurrentMetrics(); - setInterval(loadCurrentMetrics, 30000); + const refreshInterval = @(ViewBag.RefreshIntervalMilliseconds ?? 30000); + setInterval(loadCurrentMetrics, refreshInterval); \ No newline at end of file diff --git a/Watcher/Views/Server/overview.cshtml b/Watcher/Views/Server/overview.cshtml index 19bfe2e..3749077 100644 --- a/Watcher/Views/Server/overview.cshtml +++ b/Watcher/Views/Server/overview.cshtml @@ -44,8 +44,8 @@ } } - // Initial laden und dann alle 30 Sekunden + // Initial laden und dann mit konfiguriertem Intervall loadServerCards(); - setInterval(loadServerCards, 30000); + setInterval(loadServerCards, @Model.RefreshIntervalMilliseconds); } \ No newline at end of file diff --git a/Watcher/appsettings.json b/Watcher/appsettings.json index 1cfd965..df948b6 100644 --- a/Watcher/appsettings.json +++ b/Watcher/appsettings.json @@ -12,5 +12,9 @@ "ConnectionStrings": { "Sqlite": "Data Source=./persistence/watcher.db" } + }, + + "Frontend": { + "RefreshIntervalSeconds": 30 } } diff --git a/docker-compose.yaml b/docker-compose.yaml index 9c7d1a0..9e0fc40 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -18,9 +18,11 @@ services: - METRIC_RETENTION_DAYS=30 - METRIC_CLEANUP_INTERVAL_HOURS=24 - METRIC_CLEANUP_ENABLED=true + # Aktualisierungsrate Frontend + - FRONTEND_REFRESH_INTERVAL_SECONDS=30 ports: - "5000:5000" volumes: - - ./watcher-volumes/data:/app/persistence - - ./watcher-volumes/dumps:/app/wwwroot/downloads/sqlite - - ./watcher-volumes/logs:/app/logs + - ./data/db:/app/persistence + - ./data/dumps:/app/wwwroot/downloads/sqlite + - ./data/logs:/app/logs