118 lines
4.1 KiB
Plaintext
118 lines
4.1 KiB
Plaintext
|
|
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();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|