using MiaoJiZhang.Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; namespace MiaoJiZhang.Api.Services; public class AccountClosureCleanupService( IServiceScopeFactory scopeFactory, ILogger logger) : BackgroundService { protected override async Task ExecuteAsync( CancellationToken stoppingToken) { await Cleanup(stoppingToken); using var timer = new PeriodicTimer(TimeSpan.FromHours(1)); while (await timer.WaitForNextTickAsync(stoppingToken)) await Cleanup(stoppingToken); } private async Task Cleanup(CancellationToken ct) { try { using var scope = scopeFactory.CreateScope(); var db = scope.ServiceProvider.GetRequiredService(); var eraser = scope.ServiceProvider.GetRequiredService(); var ids = await db.Users .Where(user => user.AccountClosureScheduledAt.HasValue && user.AccountClosureScheduledAt <= DateTime.UtcNow) .Select(user => user.Id) .ToListAsync(ct); foreach (var userId in ids) { await eraser.EraseAsync(userId, ct); logger.LogInformation( "Permanently removed account {UserId} after closure grace period", userId); } } catch (OperationCanceledException) when (ct.IsCancellationRequested) { } catch (Exception exception) { logger.LogError(exception, "Account closure cleanup failed"); } } }