using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using ZB.MOM.WW.ScadaBridge.HealthMonitoring; namespace ZB.MOM.WW.ScadaBridge.SiteRuntime.Streaming; /// /// WP2.6d (arch-review misc — site stream alarm-vs-attribute shared buffer): site-side /// hosted service that periodically reads /// and pushes it into so /// the next carries a fresh snapshot on /// the site health report. Mirrors ScriptSchedulerStatsReporter: immediate first /// probe, fixed cadence, exceptions logged and swallowed so the loop survives every probe /// failure. /// public sealed class SiteStreamAlarmDropReporter : BackgroundService { /// Default poll cadence (10 s) — coarse enough to amortise across health reports. internal static readonly TimeSpan DefaultPollInterval = TimeSpan.FromSeconds(10); private readonly ISiteHealthCollector _collector; private readonly SiteStreamManager _streamManager; private readonly ILogger _logger; private readonly TimeSpan _pollInterval; /// Initializes a new instance of . /// The site health collector that receives the drop count. /// The site stream manager whose alarm-queue drop count is sampled. /// Logger instance. /// Poll interval override; defaults to (10 s). public SiteStreamAlarmDropReporter( ISiteHealthCollector collector, SiteStreamManager streamManager, ILogger logger, TimeSpan? pollInterval = null) { _collector = collector ?? throw new ArgumentNullException(nameof(collector)); _streamManager = streamManager ?? throw new ArgumentNullException(nameof(streamManager)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _pollInterval = pollInterval ?? DefaultPollInterval; } /// protected override async Task ExecuteAsync(CancellationToken stoppingToken) { // Immediate first probe so the first health report after start carries a // real snapshot instead of a zero. Probe(); while (!stoppingToken.IsCancellationRequested) { try { await Task.Delay(_pollInterval, stoppingToken).ConfigureAwait(false); } catch (OperationCanceledException) { break; } Probe(); } } private void Probe() { try { _collector.SetSiteStreamAlarmDropCount(_streamManager.AlarmPublishDroppedCount); } catch (Exception ex) { // Catch-all is deliberate: the hosted service must survive every class // of probe failure so the next tick gets a chance. _logger.LogWarning(ex, "SiteStreamAlarmDropReporter probe failed; next tick will retry."); } } }