using System; using System.Threading; using System.Threading.Tasks; using GmRelay.Shared.Features.Sessions.CreateSession.Wizard; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; namespace GmRelay.Bot.Features.Sessions.CreateSession.Wizard; public sealed class WizardDraftCleanupService : BackgroundService { private static readonly TimeSpan TickInterval = TimeSpan.FromMinutes(1); private readonly IWizardDraftRepository _drafts; private readonly ILogger _log; public WizardDraftCleanupService( IWizardDraftRepository drafts, ILogger log) { _drafts = drafts; _log = log; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { using var timer = new PeriodicTimer(TickInterval); try { while (await timer.WaitForNextTickAsync(stoppingToken)) { await RunOnceAsync(stoppingToken); } } catch (OperationCanceledException) { // graceful shutdown } } internal async Task RunOnceAsync(CancellationToken ct) { try { var deleted = await _drafts.DeleteExpiredAsync(ct); if (deleted > 0) { _log.LogInformation("Wizard cleanup deleted {Count} expired drafts", deleted); } } catch (OperationCanceledException) when (ct.IsCancellationRequested) { throw; } catch (Exception ex) { _log.LogError(ex, "Wizard cleanup tick failed"); } } }