Files
step3/api/QuestionsApi/Services/AnswerStatisticsMaintenanceService.cs
T

66 lines
2.5 KiB
C#

namespace QuestionsApi.Services;
public sealed class AnswerStatisticsMaintenanceService : BackgroundService
{
private readonly AnswerStatisticsStore _statistics;
private readonly QuestionAttemptStore _attempts;
private readonly ServiceMetrics _metrics;
private readonly ILogger<AnswerStatisticsMaintenanceService> _logger;
private readonly TimeSpan _interval;
private readonly string _owner = $"{Environment.MachineName}-{Guid.NewGuid():N}";
public AnswerStatisticsMaintenanceService(
AnswerStatisticsStore statistics,
QuestionAttemptStore attempts,
ServiceMetrics metrics,
IConfiguration configuration,
ILogger<AnswerStatisticsMaintenanceService> logger)
{
_statistics = statistics;
_attempts = attempts;
_metrics = metrics;
_logger = logger;
_interval = TimeSpan.FromSeconds(Math.Max(30, configuration.GetValue("AnswerStatistics:ReconcileSeconds", 300)));
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
if (await _statistics.TryAcquireBackfillLeaseAsync(_owner, TimeSpan.FromMinutes(30)))
{
_logger.LogInformation("Backfilling materialized answer statistics");
await _statistics.RebuildAllAsync();
await _statistics.MarkBackfillCompleteAsync(_owner);
_metrics.AnswerStatisticsBackfillCompleted();
_metrics.Reconciled();
}
else if (await _statistics.IsBackfillCompleteAsync())
{
_metrics.AnswerStatisticsBackfillCompleted();
}
}
catch (Exception exception)
{
_logger.LogError(exception, "Initial answer-statistics backfill failed");
}
using var timer = new PeriodicTimer(_interval);
while (await timer.WaitForNextTickAsync(stoppingToken))
{
try
{
if (await _statistics.IsBackfillCompleteAsync())
_metrics.AnswerStatisticsBackfillCompleted();
var activeIds = await _attempts.GetActiveQuestionIdsAsync(DateTime.UtcNow.Subtract(_interval).Subtract(_interval));
await _statistics.RebuildQuestionsAsync(activeIds);
_metrics.Reconciled();
}
catch (Exception exception)
{
_logger.LogError(exception, "Answer-statistics reconciliation failed");
}
}
}
}