using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using ResourceMonitorService.Configuration; using ResourceMonitorService.Services; using ResourceMonitorService.Hubs; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.DependencyInjection; namespace ResourceMonitorService { public class Worker : BackgroundService { private readonly ILogger _logger; private readonly IResourceMonitorService _resourceMonitorService; private readonly IGameDetectionService _gameDetectionService; private readonly IAlertService _alertService; private readonly MonitoringSettings _monitoringSettings; private readonly IServiceProvider _serviceProvider; public Worker( ILogger logger, IResourceMonitorService resourceMonitorService, IGameDetectionService gameDetectionService, IAlertService alertService, IOptions monitoringSettings, IServiceProvider serviceProvider) { _logger = logger; _resourceMonitorService = resourceMonitorService; _gameDetectionService = gameDetectionService; _alertService = alertService; _monitoringSettings = monitoringSettings.Value; _serviceProvider = serviceProvider; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { _logger.LogInformation("Resource Monitor background service starting..."); await BackgroundMonitoringLoop(stoppingToken); } private async Task BackgroundMonitoringLoop(CancellationToken cancellationToken) { _logger.LogInformation("Background monitoring started"); int errorCount = 0; int successfulCycles = 0; while (!cancellationToken.IsCancellationRequested) { try { // Get current resource usage var resourceUsage = await _resourceMonitorService.GetResourceUsageAsync(); // Add current game info if game detection is enabled if (_monitoringSettings.EnableGameDetection) { try { resourceUsage.RunningGame = await _gameDetectionService.GetCurrentlyRunningGameAsync(); } catch (Exception ex) { // Only log game detection errors occasionally to avoid spam if (errorCount % 12 == 0) // Every minute if 5-second intervals { _logger.LogDebug("Game detection error (suppressed): {Message}", ex.Message); } } } // Check for alerts if (_monitoringSettings.EnableAlerts) { await _alertService.CheckAndGenerateAlertsAsync(resourceUsage); } // Send real-time updates via SignalR try { using var scope = _serviceProvider.CreateScope(); var hubContext = scope.ServiceProvider.GetService>(); if (hubContext != null) { await hubContext.Clients.All.SendAsync("ResourceUpdate", resourceUsage, cancellationToken); } } catch (Exception ex) { _logger.LogDebug("SignalR broadcast error: {Message}", ex.Message); } successfulCycles++; // Log performance metrics occasionally if (successfulCycles % 4 == 0) // Every 60 seconds with 15-second intervals { _logger.LogDebug("Performance: CPU: {CpuUsage:F1}%, Memory: {MemoryUsage:F1}%, GPU: {GpuUsage}%", resourceUsage.CPU.Usage, resourceUsage.Memory.UsagePercentage, resourceUsage.GPU.Usage); } // Log successful monitoring occasionally for health verification if (successfulCycles % 120 == 0) // Every 10 minutes { _logger.LogInformation("Background monitoring healthy - completed {SuccessfulCycles} cycles", successfulCycles); } errorCount = 0; // Reset error count on success } catch (Exception ex) { errorCount++; // Only log errors occasionally to avoid spam, but always log the first few if (errorCount <= 3 || errorCount % 12 == 0) { _logger.LogError(ex, "Error in background monitoring loop (occurrence #{ErrorCount})", errorCount); } // If too many consecutive errors, increase delay if (errorCount > 10) { await Task.Delay(_monitoringSettings.UpdateIntervalMs * 2, cancellationToken); continue; } } await Task.Delay(_monitoringSettings.UpdateIntervalMs, cancellationToken); } _logger.LogInformation("Background monitoring stopped after {SuccessfulCycles} successful cycles", successfulCycles); } } }