forked from ddrilling/AsbCloudServer
108 lines
3.4 KiB
C#
108 lines
3.4 KiB
C#
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Linq;
|
|||
|
|
|||
|
namespace AsbCloudInfrastructure.Background
|
|||
|
{
|
|||
|
#nullable enable
|
|||
|
/// <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;
|
|||
|
}
|
|||
|
}
|
|||
|
#nullable disable
|
|||
|
}
|