Files

118 lines
4.1 KiB
C#
Raw Permalink Normal View History

2026-04-17 14:55:32 -04:00
using DTS.Common.Utilities.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace DTS.Common.Classes
{
/// <summary>
/// This class represents work requested of the services framework
/// </summary>
public class ServiceCall
{
public bool Started { get; set; } = false;
/// <summary>
/// the work to be done when service call is made
/// </summary>
public Action WorkAction { get; set; }
/// <summary>
/// indicates the service call is complete
/// </summary>
public void MarkDone()
{
ServiceQueue.MarkFinished(this);
}
public string Name { get; set; }
public ServiceCall(string name)
{
Name = name;
}
}
/// <summary>
/// this class handles calls of the services framework by doing a little managing of who gets to run and when
/// </summary>
public class ServiceQueue
{
/// <summary>
/// just a lock to keep resource access thread safe
/// </summary>
private static readonly object QueueLock = new object();
/// <summary>
/// this is sort of a Queue, actions are enqueued when the are instantiated,
/// but using a list allows us to re-order then when needed and to remove items that are no longer needed and haven't been
/// started yet
/// </summary>
private readonly List<ServiceCall> ServiceCalls = new List<ServiceCall>();
/// <summary>
/// the singleton/the instance of the queue
/// </summary>
private static ServiceQueue _serviceQueue = new ServiceQueue();
/// <summary>
/// adds a new item for the services framework to handle
/// </summary>
/// <param name="call"></param>
public static void Enqueue(ServiceCall call)
{
lock (QueueLock)
{
//adds work item to the queue
_serviceQueue.ServiceCalls.Add(call);
//start the item if it's the only item in the queue
if (1 == _serviceQueue.ServiceCalls.Count)
{
StartWork();
}
}
}
/// <summary>
/// starts a call into the services framework
/// </summary>
private static void StartWork()
{
lock (QueueLock)
{
//if there's any calls in the queue, launch the first
if (_serviceQueue.ServiceCalls.Any())
{
var work = _serviceQueue.ServiceCalls[0];
//to prevent multiple startworks from starting the same work, just make sure it's not started
if (work.Started) { return; }
work.Started = true;
Task.Run(() => { work.WorkAction(); });
}
}
}
/// <summary>
/// marks a servicecall as finished, if it's the current work item the next work item will be started if any
/// </summary>
/// <param name="call"></param>
public static void MarkFinished(ServiceCall call)
{
lock (QueueLock)
{
if (!_serviceQueue.ServiceCalls.Any() || !_serviceQueue.ServiceCalls.Contains(call))
{
return;
}
if (_serviceQueue.ServiceCalls[0] != call)
{
//it wasn't being actively worked on, just remove
_serviceQueue.ServiceCalls.Remove(call);
return;
}
//this was the current work item, so we are free to start a new item
_serviceQueue.ServiceCalls.RemoveAt(0);
if (_serviceQueue.ServiceCalls.Any())
{
StartWork();
}
}
}
}
}