* Added mising XML summaries
* Obsolete code comments cleanup
This commit is contained in:
@@ -1,11 +1,23 @@
|
|||||||
namespace Telegrator.Handlers
|
namespace Telegrator.Handlers
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents handler results, allowing to communicate with router and control aspect execution
|
||||||
|
/// </summary>
|
||||||
public sealed class Result
|
public sealed class Result
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Is result positive
|
||||||
|
/// </summary>
|
||||||
public bool Positive { get; }
|
public bool Positive { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Should router search for next matching handler
|
||||||
|
/// </summary>
|
||||||
public bool RouteNext { get; }
|
public bool RouteNext { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Exact type that router should search
|
||||||
|
/// </summary>
|
||||||
public Type? NextType { get; }
|
public Type? NextType { get; }
|
||||||
|
|
||||||
internal Result(bool positive, bool routeNext, Type? nextType)
|
internal Result(bool positive, bool routeNext, Type? nextType)
|
||||||
@@ -15,15 +27,32 @@
|
|||||||
NextType = nextType;
|
NextType = nextType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "OK" result
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
public static Result Ok()
|
public static Result Ok()
|
||||||
=> new Result(true, false, null);
|
=> new Result(true, false, null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Somethong went wrong" result
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
public static Result Fault()
|
public static Result Fault()
|
||||||
=> new Result(false, false, null);
|
=> new Result(false, false, null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Search next handler" result
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
public static Result Next()
|
public static Result Next()
|
||||||
=> new Result(true, true, null);
|
=> new Result(true, true, null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Search next handler of type" result
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
public static Result Next<T>()
|
public static Result Next<T>()
|
||||||
=> new Result(true, true, typeof(T));
|
=> new Result(true, true, typeof(T));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,21 @@ using System.Collections.Concurrent;
|
|||||||
|
|
||||||
namespace Telegrator.Polling
|
namespace Telegrator.Polling
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a dictionayr with limited number of slots, if trying to overflow, will block calling thread until one of slots will be free
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TKey"></typeparam>
|
||||||
|
/// <typeparam name="TValue"></typeparam>
|
||||||
public class LimitedDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>, IDisposable
|
public class LimitedDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>, IDisposable
|
||||||
{
|
{
|
||||||
private readonly int? _maximum;
|
private readonly int? _maximum;
|
||||||
private readonly SemaphoreSlim _semaphore = null!;
|
private readonly SemaphoreSlim _semaphore = null!;
|
||||||
private readonly ConcurrentDictionary<TKey, TValue> _dict = [];
|
private readonly ConcurrentDictionary<TKey, TValue> _dict = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes new instance of <see cref="LimitedDictionary{TKey, TValue}"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="maximum"></param>
|
||||||
public LimitedDictionary(int? maximum)
|
public LimitedDictionary(int? maximum)
|
||||||
{
|
{
|
||||||
_maximum = maximum;
|
_maximum = maximum;
|
||||||
@@ -19,6 +28,14 @@ namespace Telegrator.Polling
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to add new element to dictioanry.
|
||||||
|
/// If all slots are occupied, blocks calling thread.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
/// <param name="value"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
public async Task<bool> Add(TKey key, TValue value, CancellationToken cancellationToken)
|
public async Task<bool> Add(TKey key, TValue value, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (_semaphore != null)
|
if (_semaphore != null)
|
||||||
@@ -27,6 +44,13 @@ namespace Telegrator.Polling
|
|||||||
return _dict.TryAdd(key, value);
|
return _dict.TryAdd(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to remove element from dictionay.
|
||||||
|
/// Frees slot on success.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
/// <param name="result"></param>
|
||||||
|
/// <returns></returns>
|
||||||
public bool Remove(TKey key, out TValue result)
|
public bool Remove(TKey key, out TValue result)
|
||||||
{
|
{
|
||||||
if (_dict.TryRemove(key, out result))
|
if (_dict.TryRemove(key, out result))
|
||||||
@@ -38,8 +62,10 @@ namespace Telegrator.Polling
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => _dict.GetEnumerator();
|
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => _dict.GetEnumerator();
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
IEnumerator IEnumerable.GetEnumerator() => _dict.GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => _dict.GetEnumerator();
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace Telegrator.Polling
|
namespace Telegrator.Polling
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
public class LimitedQueue<T>
|
public class LimitedQueue<T>
|
||||||
{
|
{
|
||||||
private readonly int? _maximum;
|
private readonly int? _maximum;
|
||||||
@@ -39,4 +40,5 @@ namespace Telegrator.Polling
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Collections.Concurrent;
|
using Telegrator.Handlers;
|
||||||
using Telegrator.Handlers;
|
|
||||||
using Telegrator.MadiatorCore;
|
using Telegrator.MadiatorCore;
|
||||||
using Telegrator.MadiatorCore.Descriptors;
|
using Telegrator.MadiatorCore.Descriptors;
|
||||||
|
|
||||||
@@ -16,34 +15,11 @@ namespace Telegrator.Polling
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected object SyncObj = new object();
|
protected object SyncObj = new object();
|
||||||
|
|
||||||
/*
|
|
||||||
/// <summary>
|
|
||||||
/// Event that signals when awaiting handlers are queued.
|
|
||||||
/// </summary>
|
|
||||||
protected ManualResetEventSlim AwaitingHandlersQueuedEvent = null!;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Semaphore for controlling the number of concurrently executing handlers.
|
/// Semaphore for controlling the number of concurrently executing handlers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected SemaphoreSlim ExecutingHandlersSemaphore = null!;
|
protected SemaphoreSlim ExecutingHandlersSemaphore = null!;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Queue for storing awaiting handlers.
|
|
||||||
/// </summary>
|
|
||||||
protected readonly ConcurrentQueue<DescribedHandlerInfo> AwaitingHandlersQueue = [];
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Dictionary for tracking currently executing handlers.
|
|
||||||
/// </summary>
|
|
||||||
protected readonly ConcurrentDictionary<HandlerLifetimeToken, Task> ExecutingHandlersPool = [];
|
|
||||||
*/
|
|
||||||
|
|
||||||
//protected readonly ConcurrentDictionary<Type, LimitedQueue<DescribedHandlerInfo>> AwaitingHandlersQueue;
|
|
||||||
|
|
||||||
//protected readonly LimitedDictionary<HandlerLifetimeToken, Task> ExecutingHandlersPool;
|
|
||||||
|
|
||||||
protected SemaphoreSlim ExecutingHandlersSemaphore = null!;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The bot configuration options.
|
/// The bot configuration options.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -74,26 +50,16 @@ namespace Telegrator.Polling
|
|||||||
{
|
{
|
||||||
Options = options;
|
Options = options;
|
||||||
GlobalCancellationToken = globalCancellationToken;
|
GlobalCancellationToken = globalCancellationToken;
|
||||||
//AwaitingHandlersQueue = new ConcurrentDictionary<Type, LimitedQueue<DescribedHandlerInfo>>();
|
|
||||||
//ExecutingHandlersPool = new LimitedDictionary<HandlerLifetimeToken, Task>(options.MaximumParallelWorkingHandlers);
|
|
||||||
|
|
||||||
if (options.MaximumParallelWorkingHandlers != null)
|
if (options.MaximumParallelWorkingHandlers != null)
|
||||||
{
|
{
|
||||||
ExecutingHandlersSemaphore = new SemaphoreSlim(options.MaximumParallelWorkingHandlers.Value);
|
ExecutingHandlersSemaphore = new SemaphoreSlim(options.MaximumParallelWorkingHandlers.Value);
|
||||||
//AwaitingHandlersQueuedEvent = new ManualResetEventSlim(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
if (Options.MaximumParallelWorkingHandlers != null)
|
|
||||||
HandlersCheckpoint();
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task Enqueue(IEnumerable<DescribedHandlerInfo> handlers)
|
public async Task Enqueue(IEnumerable<DescribedHandlerInfo> handlers)
|
||||||
{
|
{
|
||||||
//handlers.ForEach(Enqueue);
|
|
||||||
|
|
||||||
Result? lastResult = null;
|
Result? lastResult = null;
|
||||||
foreach (DescribedHandlerInfo handlerInfo in handlers)
|
foreach (DescribedHandlerInfo handlerInfo in handlers)
|
||||||
{
|
{
|
||||||
@@ -124,137 +90,6 @@ namespace Telegrator.Polling
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public void Enqueue(DescribedHandlerInfo handlerInfo)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
|
|
||||||
if (Options.MaximumParallelWorkingHandlers == null)
|
|
||||||
{
|
|
||||||
Task.Run(async () => await ExecuteHandlerWrapper(handlerInfo));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (SyncObj)
|
|
||||||
{
|
|
||||||
AwaitingHandlersQueue.Enqueue(handlerInfo);
|
|
||||||
HandlerEnqueued?.Invoke(handlerInfo);
|
|
||||||
AwaitingHandlersQueuedEvent.Set();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public void Dequeue(HandlerLifetimeToken token)
|
|
||||||
{
|
|
||||||
if (Options.MaximumParallelWorkingHandlers == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
lock (SyncObj)
|
|
||||||
{
|
|
||||||
ExecutingHandlersPool.TryRemove(token, out _);
|
|
||||||
ExecutingHandlersSemaphore.Release(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
/// <summary>
|
|
||||||
/// Main checkpoint method that manages handler execution in a loop.
|
|
||||||
/// Continuously processes queued handlers while respecting concurrency limits.
|
|
||||||
/// </summary>
|
|
||||||
protected virtual async void HandlersCheckpoint()
|
|
||||||
{
|
|
||||||
await Task.Yield();
|
|
||||||
while (!GlobalCancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
if (!CanEnqueueHandler())
|
|
||||||
{
|
|
||||||
await ExecutingHandlersSemaphore.WaitAsync(GlobalCancellationToken);
|
|
||||||
if (!CanEnqueueHandler())
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!TryDequeueHandler(out DescribedHandlerInfo? enqueuedHandler))
|
|
||||||
{
|
|
||||||
AwaitingHandlersQueuedEvent.Reset();
|
|
||||||
AwaitingHandlersQueuedEvent.Wait(GlobalCancellationToken);
|
|
||||||
|
|
||||||
if (!TryDequeueHandler(out enqueuedHandler))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enqueuedHandler == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ExecuteHandler(enqueuedHandler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Executes a handler by creating a lifetime token and tracking the execution.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="enqueuedHandler">The handler to execute.</param>
|
|
||||||
protected virtual void ExecuteHandler(DescribedHandlerInfo enqueuedHandler)
|
|
||||||
{
|
|
||||||
HandlerLifetimeToken lifetimeToken = enqueuedHandler.HandlerLifetime;
|
|
||||||
lifetimeToken.OnLifetimeEnded += Dequeue;
|
|
||||||
|
|
||||||
Task executingHandler = ExecuteHandlerWrapper(enqueuedHandler);
|
|
||||||
lock (SyncObj)
|
|
||||||
ExecutingHandlersPool.TryAdd(lifetimeToken, executingHandler);
|
|
||||||
|
|
||||||
HandlerExecuting?.Invoke(enqueuedHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Wrapper method that executes a handler and handles exceptions.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="enqueuedHandler">The handler to execute.</param>
|
|
||||||
/// <returns>A task representing the asynchronous execution.</returns>
|
|
||||||
/// <exception cref="HandlerFaultedException">Thrown when the handler execution fails.</exception>
|
|
||||||
protected virtual async Task ExecuteHandlerWrapper(DescribedHandlerInfo enqueuedHandler)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await enqueuedHandler.Execute(GlobalCancellationToken);
|
|
||||||
}
|
|
||||||
catch (OperationCanceledException)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
throw new HandlerFaultedException(enqueuedHandler, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if a new handler can be enqueued based on the current execution count.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>True if a new handler can be enqueued; otherwise, false.</returns>
|
|
||||||
protected virtual bool CanEnqueueHandler()
|
|
||||||
{
|
|
||||||
lock (SyncObj)
|
|
||||||
{
|
|
||||||
return ExecutingHandlersPool.Count < Options.MaximumParallelWorkingHandlers;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attempts to dequeue a handler from the awaiting queue.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="enqueuedHandler">The dequeued handler, if successful.</param>
|
|
||||||
/// <returns>True if a handler was successfully dequeued; otherwise, false.</returns>
|
|
||||||
protected virtual bool TryDequeueHandler(out DescribedHandlerInfo? enqueuedHandler)
|
|
||||||
{
|
|
||||||
lock (SyncObj)
|
|
||||||
{
|
|
||||||
return AwaitingHandlersQueue.TryDequeue(out enqueuedHandler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Disposes of the handlers pool and releases all resources.
|
/// Disposes of the handlers pool and releases all resources.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user