using System; using System.Collections.Generic; using System.Linq; namespace AsbCloudInfrastructure.Background { /// <summary> /// <para> /// Очередь работ /// </para> /// Не периодические задачи будут возвращаться первыми, как самые приоритетные. /// </summary> class WorkQueue { private Queue<WorkBase> Primary = new(8); private readonly List<WorkPeriodic> Periodic = new(8); /// <summary> /// Добавление работы. /// </summary> /// <param name="work"></param> /// <exception cref="ArgumentException">Id mast be unique</exception> public void Push(WorkBase work) { if (Periodic.Any(w => w.Id == work.Id)) throw new ArgumentException("work.Id is not unique", nameof(work)); if (Primary.Any(w => w.Id == work.Id)) throw new ArgumentException("work.Id is not unique", nameof(work)); if (work is WorkPeriodic workPeriodic) { Periodic.Add(workPeriodic); return; } Primary.Enqueue(work); } /// <summary> /// Удаление работы по ID /// </summary> /// <param name="id"></param> /// <returns></returns> public bool Delete(string id) { var workPeriodic = Periodic.FirstOrDefault(w => w.Id == id); if (workPeriodic is not null) { Periodic.Remove(workPeriodic); return true; } var work = Primary.FirstOrDefault(w => w.Id == id); if (work is not null) { Primary = new Queue<WorkBase>(Primary.Where(w => w.Id != id)); return true; } return false; } public bool Contains(string id) { var result = Periodic.Any(w => w.Id == id) || Primary.Any(w => w.Id == id); return result; } /// <summary> /// <para> /// Возвращает приоритетную задачу. /// </para> /// <para> /// Если приоритетные закончились, то ищет ближайшую периодическую. /// Если до старта ближайшей периодической работы меньше 20 сек, /// то этой задаче устанавливается время последнего запуска в now и она возвращается. /// Если больше 20 сек, то возвращается null. /// </para> /// </summary> /// <param name="maxTimeToNextWork"></param> /// <returns></returns> public WorkBase? Pop() { if (Primary.Any()) return Primary.Dequeue(); var work = GetNextPeriodic(); if (work is null || work.NextStart > DateTime.Now) return null; work.LastStart = DateTime.Now; return work; } private WorkPeriodic? GetNextPeriodic() { var work = Periodic .OrderBy(w => w.NextStart) .ThenByDescending(w => w.Period) .FirstOrDefault(); return work; } } }