using System;
using System.Collections.Generic;
using System.Linq;
namespace AsbCloudInfrastructure.Background;
///
///
/// Очередь работ
///
/// Не периодические задачи будут возвращаться первыми, как самые приоритетные.
///
public class WorkStore
{
private readonly List periodics = new(8);
///
/// Список периодических задач
///
public IEnumerable Periodics => periodics;
///
/// Работы выполняемые один раз
///
public Queue RunOnceQueue { get; private set; } = new(8);
///
/// Завершившиеся с ошибкой
///
public CyclycArray Felled { get; } = new(16);
///
/// Добавить фоновую работу выполняющуюся с заданным периодом
///
///
///
public void AddPeriodic(TimeSpan period)
where T : Work, new()
{
var work = new T();
var periodic = new WorkPeriodic(work, period);
periodics.Add(periodic);
}
///
/// Добавить фоновую работу выполняющуюся с заданным периодом
///
///
///
public void AddPeriodic(Work work, TimeSpan period)
{
var periodic = new WorkPeriodic(work, period);
periodics.Add(periodic);
}
///
/// Удаление работы по ID из одноразовой очереди
///
///
///
public bool TryRemoveFromRunOnceQueue(string id)
{
var work = RunOnceQueue.FirstOrDefault(w => w.Id == id);
if (work is not null)
{
RunOnceQueue = new Queue(RunOnceQueue.Where(w => w.Id != id));
return true;
}
return false;
}
///
///
/// Возвращает приоритетную задачу.
///
///
/// Если приоритетные закончились, то ищет ближайшую периодическую.
/// Если до старта ближайшей периодической работы меньше 20 сек,
/// то этой задаче устанавливается время последнего запуска в now и она возвращается.
/// Если больше 20 сек, то возвращается null.
///
///
///
///
public Work? GetNext()
{
if (RunOnceQueue.Any())
return RunOnceQueue.Dequeue();
var work = GetNextPeriodic();
if (work is null || work.NextStart > DateTime.Now)
return null;
return work.Work;
}
private WorkPeriodic? GetNextPeriodic()
{
var work = Periodics
.OrderBy(w => w.NextStart)
.FirstOrDefault();
return work;
}
}