Scale unique answer tracking
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
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.Reconciled();
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.LogError(exception, "Initial answer-statistics backfill failed");
|
||||
}
|
||||
|
||||
using var timer = new PeriodicTimer(_interval);
|
||||
while (await timer.WaitForNextTickAsync(stoppingToken))
|
||||
{
|
||||
try
|
||||
{
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user