using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Transport; namespace ZB.MOM.WW.ScadaBridge.Transport.Import; /// /// T-007: periodic background sweep that drives /// so abandoned import sessions clear from memory on their own, without needing a /// new to trigger lazy eviction. Each session /// owns the decrypted bundle content (potentially up to ~100 MB of secrets — DB /// connection strings, SMTP credentials, external-system auth configs), and the /// design contract is "bundles are not retained server-side after ApplyAsync /// commits". This service keeps abandoned / failed sessions from pinning that /// plaintext for the full 30-minute TTL when no other traffic flows. /// internal sealed class BundleSessionEvictionService : BackgroundService { private static readonly TimeSpan SweepInterval = TimeSpan.FromMinutes(1); private readonly IBundleSessionStore _sessionStore; private readonly ILogger _logger; /// /// Initializes a new instance of . /// /// The bundle session store to sweep for expired sessions. /// Logger for sweep diagnostics. public BundleSessionEvictionService( IBundleSessionStore sessionStore, ILogger logger) { _sessionStore = sessionStore ?? throw new ArgumentNullException(nameof(sessionStore)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } /// protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { try { await Task.Delay(SweepInterval, stoppingToken).ConfigureAwait(false); } catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested) { return; } try { _sessionStore.EvictExpired(); } catch (Exception ex) { _logger.LogWarning(ex, "Bundle session sweep failed; will retry on next interval."); } } } }