87 lines
2.9 KiB
C#
87 lines
2.9 KiB
C#
using System;
|
|
using Svrnty.CQRS.Events.Abstractions.Storage;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Logging;
|
|
using Svrnty.CQRS.Events.Abstractions;
|
|
|
|
namespace Svrnty.CQRS.Events.Services;
|
|
|
|
/// <summary>
|
|
/// Background service that periodically cleans up old idempotency records.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This service cleans up:
|
|
/// - Old processed event records (older than retention period)
|
|
/// - Expired idempotency locks (automatically handled by the store)
|
|
/// </remarks>
|
|
public class IdempotencyCleanupService : BackgroundService
|
|
{
|
|
private readonly IIdempotencyStore _idempotencyStore;
|
|
private readonly ILogger<IdempotencyCleanupService> _logger;
|
|
|
|
// Configuration - these could be made configurable via options
|
|
private readonly TimeSpan _cleanupInterval = TimeSpan.FromHours(1);
|
|
private readonly TimeSpan _retentionPeriod = TimeSpan.FromDays(7);
|
|
|
|
public IdempotencyCleanupService(
|
|
IIdempotencyStore idempotencyStore,
|
|
ILogger<IdempotencyCleanupService> logger)
|
|
{
|
|
_idempotencyStore = idempotencyStore ?? throw new ArgumentNullException(nameof(idempotencyStore));
|
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
|
}
|
|
|
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|
{
|
|
_logger.LogInformation(
|
|
"Idempotency cleanup service started (Interval: {Interval}, Retention: {Retention})",
|
|
_cleanupInterval,
|
|
_retentionPeriod);
|
|
|
|
while (!stoppingToken.IsCancellationRequested)
|
|
{
|
|
try
|
|
{
|
|
await Task.Delay(_cleanupInterval, stoppingToken);
|
|
|
|
if (stoppingToken.IsCancellationRequested)
|
|
break;
|
|
|
|
await PerformCleanupAsync(stoppingToken);
|
|
}
|
|
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
|
|
{
|
|
// Normal shutdown
|
|
break;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error during idempotency cleanup");
|
|
// Continue running despite errors
|
|
}
|
|
}
|
|
|
|
_logger.LogInformation("Idempotency cleanup service stopped");
|
|
}
|
|
|
|
private async Task PerformCleanupAsync(CancellationToken cancellationToken)
|
|
{
|
|
var olderThan = DateTimeOffset.UtcNow.Subtract(_retentionPeriod);
|
|
|
|
_logger.LogDebug("Starting idempotency cleanup (deleting records older than {OlderThan})", olderThan);
|
|
|
|
var deletedCount = await _idempotencyStore.CleanupAsync(olderThan, cancellationToken);
|
|
|
|
if (deletedCount > 0)
|
|
{
|
|
_logger.LogInformation("Cleaned up {DeletedCount} old idempotency records", deletedCount);
|
|
}
|
|
else
|
|
{
|
|
_logger.LogDebug("No old idempotency records to clean up");
|
|
}
|
|
}
|
|
}
|