using System;
using System.Collections.Generic;
using System.Linq;
namespace AsbCloudInfrastructure.Background
{
///
///
/// Очередь работ
///
/// Не периодические задачи будут возвращаться первыми, как самые приоритетные.
///
class WorkQueue
{
private Queue Primary = new(8);
private readonly List Periodic = new(8);
///
/// Добавление работы.
///
///
/// Id mast be unique
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);
}
///
/// Удаление работы по ID
///
///
///
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(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;
}
///
///
/// Возвращает приоритетную задачу.
///
///
/// Если приоритетные закончились, то ищет ближайшую периодическую.
/// Если до старта ближайшей периодической работы меньше 20 сек,
/// то этой задаче устанавливается время последнего запуска в now и она возвращается.
/// Если больше 20 сек, то возвращается null.
///
///
///
///
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;
}
}
}