From e2d011f115dd8137692407f32f7a705e18202da0 Mon Sep 17 00:00:00 2001 From: Oliver Kieselbach Date: Mon, 6 Apr 2026 14:06:58 +0200 Subject: [PATCH] enhanced DO collector again --- .../DeliveryOptimizationCollector.cs | 27 ++++++++++++++++++- .../MonitoringService.CollectorLifecycle.cs | 2 +- .../AutopilotMonitor.Agent/buildcounter.txt | 2 +- .../Models/Config/AgentConfigResponse.cs | 6 ++--- 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Collectors/DeliveryOptimizationCollector.cs b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Collectors/DeliveryOptimizationCollector.cs index 59d66d61..b9a19d66 100644 --- a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Collectors/DeliveryOptimizationCollector.cs +++ b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Collectors/DeliveryOptimizationCollector.cs @@ -36,6 +36,7 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Collectors private bool _permanentlyDisabled; private int _consecutiveErrors; private volatile bool _dormant = true; + private int _collecting; // concurrency guard (0 = idle, 1 = collecting) // Track which apps we already sent final do_telemetry for (prevents duplicate callbacks) private readonly HashSet _enrichedAppIds = new HashSet(StringComparer.OrdinalIgnoreCase); @@ -92,6 +93,25 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Collectors { if (_permanentlyDisabled || _dormant) return; + // Concurrency guard: Runspace is not thread-safe. Skip if previous poll is still running. + if (Interlocked.CompareExchange(ref _collecting, 1, 0) != 0) + { + Logger.Debug("[DeliveryOptimizationCollector] Skipping poll — previous invocation still running"); + return; + } + try + { + CollectCore(); + } + finally + { + Interlocked.Exchange(ref _collecting, 0); + } + } + + private void CollectCore() + { + // Guard: check if there's still work to do var packageStates = _getPackageStates(); if (packageStates == null || packageStates.Count == 0) return; @@ -325,7 +345,12 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Collectors Data = new Dictionary { ["appId"] = appId, - ["name"] = pkg.Name, + ["appName"] = pkg.Name, + // UI-compatible fields (DownloadProgress.tsx reads these) + ["bytesDownloaded"] = totalBytes, + ["bytesTotal"] = fileSize, + ["progressPercent"] = percentComplete, + // DO-specific fields ["doFileSize"] = fileSize, ["doTotalBytesDownloaded"] = totalBytes, ["doPercentComplete"] = percentComplete, diff --git a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Core/MonitoringService.CollectorLifecycle.cs b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Core/MonitoringService.CollectorLifecycle.cs index a95c6a70..7ca51551 100644 --- a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Core/MonitoringService.CollectorLifecycle.cs +++ b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Core/MonitoringService.CollectorLifecycle.cs @@ -110,7 +110,7 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Core // Delivery Optimization collector — polls OS-level DO status for peer caching telemetry if (collectors?.EnableDeliveryOptimizationCollector != false && _enrollmentTracker != null) { - var doInterval = collectors?.DeliveryOptimizationIntervalSeconds ?? 5; + var doInterval = collectors?.DeliveryOptimizationIntervalSeconds ?? 3; _deliveryOptimizationCollector = new DeliveryOptimizationCollector( _configuration.SessionId, _configuration.TenantId, diff --git a/src/Agent/AutopilotMonitor.Agent/buildcounter.txt b/src/Agent/AutopilotMonitor.Agent/buildcounter.txt index ea8789a6..bde83afb 100644 --- a/src/Agent/AutopilotMonitor.Agent/buildcounter.txt +++ b/src/Agent/AutopilotMonitor.Agent/buildcounter.txt @@ -1 +1 @@ -854 +855 diff --git a/src/Shared/AutopilotMonitor.Shared/Models/Config/AgentConfigResponse.cs b/src/Shared/AutopilotMonitor.Shared/Models/Config/AgentConfigResponse.cs index 26a23273..2c1710ba 100644 --- a/src/Shared/AutopilotMonitor.Shared/Models/Config/AgentConfigResponse.cs +++ b/src/Shared/AutopilotMonitor.Shared/Models/Config/AgentConfigResponse.cs @@ -249,10 +249,10 @@ namespace AutopilotMonitor.Shared.Models /// /// Interval in seconds for polling Get-DeliveryOptimizationStatus. - /// Only polls when active downloads are detected. - /// Default: 5 seconds + /// Only polls when active downloads are detected (dormant otherwise). + /// Default: 3 seconds /// - public int DeliveryOptimizationIntervalSeconds { get; set; } = 5; + public int DeliveryOptimizationIntervalSeconds { get; set; } = 3; /// /// Creates default collector configuration