feat(core,dal,domain,snapshotWorker): Воркер по управлению снапшотами. Создание сгапшотов для таблицы RobotConfigurations
This commit is contained in:
114
PARR.SnapshotWorker/Worker.cs
Normal file
114
PARR.SnapshotWorker/Worker.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
using PARR.Core.Common.Interfaces;
|
||||
using PARR.Core.Services.Snapshots.Interfaces;
|
||||
|
||||
namespace PARR.SnapshotWorker
|
||||
{
|
||||
public class Worker : BackgroundService
|
||||
{
|
||||
private readonly ILogger<Worker> _logger;
|
||||
private readonly IIntervalService _intervalService;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
// Хранилище времени СЛЕДУЮЩЕГО запуска для каждого сервиса
|
||||
private readonly Dictionary<string, DateTimeOffset> _nextRunTimers = new();
|
||||
|
||||
// День последней успешной очистки базы данных
|
||||
private int _lastCleanupDay = -1;
|
||||
|
||||
// Интервал, должен быть меньше минуты, чтобы попадать во все возможные интервалы
|
||||
TimeSpan tickInterval = TimeSpan.FromSeconds(25);
|
||||
|
||||
public Worker(
|
||||
ILogger<Worker> logger,
|
||||
IIntervalService intervalService,
|
||||
IServiceProvider serviceProvider
|
||||
)
|
||||
{
|
||||
_logger = logger;
|
||||
_intervalService = intervalService;
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
_logger.LogInformation("Запуск фонового сервиса создания системных снапшотов");
|
||||
|
||||
await _intervalService.IntervalInitAsync(async () =>
|
||||
{
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
|
||||
using (var scope = _serviceProvider.CreateScope())
|
||||
{
|
||||
// Собираем абсолютно все зарегистрированные сервисы снапшотов
|
||||
var providers = scope.ServiceProvider.GetServices<ISnapshotProvider>();
|
||||
|
||||
#region Параллельный сбор снапшотов
|
||||
|
||||
var tasksToRun = new List<Task>();
|
||||
|
||||
foreach (var provider in providers)
|
||||
{
|
||||
var providerKey = provider.GetType().FullName!;
|
||||
|
||||
// Если сервис видим впервые, планируем его первый старт прямо сейчас
|
||||
if (!_nextRunTimers.ContainsKey(providerKey))
|
||||
{
|
||||
_nextRunTimers[providerKey] = now;
|
||||
}
|
||||
|
||||
// Если текущее время добежало до запланированного «будильника»
|
||||
if (now >= _nextRunTimers[providerKey])
|
||||
{
|
||||
// СРАЗУ планируем следующий старт, чтобы сетка времени не съезжала
|
||||
// из-за времени выполнения самого метода
|
||||
_nextRunTimers[providerKey] = now.Add(provider.Interval);
|
||||
|
||||
// Добавляем таску в список для параллельного выполнения (без await!)
|
||||
tasksToRun.Add(ExecuteSafelyAsync(provider, () => provider.TakeSnapshotAsync(stoppingToken), "Создание снапшота"));
|
||||
}
|
||||
}
|
||||
|
||||
// Запускаем все готовые снапшоты ОДНОВРЕМЕННО
|
||||
if (tasksToRun.Any())
|
||||
{
|
||||
await Task.WhenAll(tasksToRun);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Ежедневная очистка БД
|
||||
|
||||
// Если наступили новые сутки в формате UTC — запускаем ротацию старых данных
|
||||
if (now.Day != _lastCleanupDay)
|
||||
{
|
||||
_logger.LogInformation("Наступили новые сутки. Запуск процесса очистки устаревших снапшотов...");
|
||||
|
||||
foreach (var provider in providers)
|
||||
{
|
||||
await ExecuteSafelyAsync(provider, () => provider.CleanUpOldSnapshotsAsync(stoppingToken), "Очистка старых данных");
|
||||
}
|
||||
|
||||
// Запоминаем, что за сегодня очистку уже провели успешно
|
||||
_lastCleanupDay = now.Day;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
}, tickInterval);
|
||||
}
|
||||
|
||||
private async Task ExecuteSafelyAsync(ISnapshotProvider provider, Func<Task> action, string operationName)
|
||||
{
|
||||
try
|
||||
{
|
||||
await action();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Критическая ошибка во время операции '{Operation}' в сервисе {ProviderName}", operationName, provider.GetType().Name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user