using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using ScadaLink.Commons.Messages.Health; namespace ScadaLink.HealthMonitoring; /// /// Periodically collects a SiteHealthReport and sends it to central via Akka remoting. /// Sequence numbers are monotonic, starting at 1, and reset on service restart. /// public class HealthReportSender : BackgroundService { private readonly ISiteHealthCollector _collector; private readonly IHealthReportTransport _transport; private readonly HealthMonitoringOptions _options; private readonly ILogger _logger; private readonly string _siteId; private long _sequenceNumber; public HealthReportSender( ISiteHealthCollector collector, IHealthReportTransport transport, IOptions options, ILogger logger, ISiteIdentityProvider siteIdentityProvider) { _collector = collector; _transport = transport; _options = options.Value; _logger = logger; _siteId = siteIdentityProvider.SiteId; } /// /// Current sequence number (for testing). /// public long CurrentSequenceNumber => Interlocked.Read(ref _sequenceNumber); protected override async Task ExecuteAsync(CancellationToken stoppingToken) { _logger.LogInformation( "Health report sender starting for site {SiteId}, interval {Interval}s", _siteId, _options.ReportInterval.TotalSeconds); using var timer = new PeriodicTimer(_options.ReportInterval); while (await timer.WaitForNextTickAsync(stoppingToken).ConfigureAwait(false)) { try { // TODO: Wire S&F buffer depths when StoreAndForward service is available in DI // e.g., var depths = await _bufferDepthProvider.GetDepthsAsync(); // _collector.SetStoreAndForwardDepths(depths); var seq = Interlocked.Increment(ref _sequenceNumber); var report = _collector.CollectReport(_siteId); // Replace the placeholder sequence number with our monotonic one var reportWithSeq = report with { SequenceNumber = seq }; _transport.Send(reportWithSeq); _logger.LogDebug("Sent health report #{Seq} for site {SiteId}", seq, _siteId); } catch (Exception ex) { _logger.LogWarning(ex, "Failed to send health report for site {SiteId}", _siteId); // Continue sending — don't let a single failure stop reporting } } } }