using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using MxGateway.Server.Configuration; namespace MxGateway.Server.Sessions; public sealed class SessionLeaseMonitorHostedService( ISessionManager sessionManager, IOptions options, ILogger logger, TimeProvider? timeProvider = null) : BackgroundService { private readonly TimeProvider _timeProvider = timeProvider ?? TimeProvider.System; protected override async Task ExecuteAsync(CancellationToken stoppingToken) { TimeSpan interval = TimeSpan.FromSeconds(Math.Max(1, options.Value.Sessions.LeaseSweepIntervalSeconds)); using PeriodicTimer timer = new(interval, _timeProvider); try { while (await timer.WaitForNextTickAsync(stoppingToken).ConfigureAwait(false)) { try { await sessionManager .CloseExpiredLeasesAsync(_timeProvider.GetUtcNow(), stoppingToken) .ConfigureAwait(false); } catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested) { return; } catch (Exception exception) { logger.LogWarning(exception, "Session lease sweep failed."); } } } catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested) { } } }