You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
100 lines
2.1 KiB
100 lines
2.1 KiB
using System.Collections.Concurrent;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
namespace Connected.Collections.Concurrent;
|
|
|
|
internal sealed class QueuedDispatcher<TArgs, TJob> : IDispatcher<TArgs, TJob>
|
|
where TJob : IDispatcherJob<TArgs>
|
|
{
|
|
public event EventHandler? Completed;
|
|
|
|
public QueuedDispatcher(IDispatcher<TArgs, TJob> dispatcher, string queueName)
|
|
{
|
|
Dispatcher = dispatcher;
|
|
Queue = new();
|
|
QueueName = queueName;
|
|
|
|
/*
|
|
* Dispatcher jobs should be transient so it's safe to request a service from the root collection.
|
|
*/
|
|
if (CollectionsStartup.Application?.Services.GetService<DispatcherJob<TArgs>>() is not DispatcherJob<TArgs> job)
|
|
throw new SysException(this, $"{SR.ErrCreateService} ({typeof(DispatcherJob<TArgs>).Name})");
|
|
|
|
job.Completed += OnCompleted;
|
|
|
|
Job = job;
|
|
}
|
|
|
|
public CancellationToken CancellationToken => Dispatcher.CancellationToken;
|
|
public bool IsDisposed { get; private set; }
|
|
public DispatcherProcessBehavior Behavior => DispatcherProcessBehavior.Queued;
|
|
public string QueueName { get; }
|
|
private DispatcherJob<TArgs> Job { get; set; }
|
|
private IDispatcher<TArgs, TJob> Dispatcher { get; set; }
|
|
public int Count => Queue.Count;
|
|
private ConcurrentQueue<TArgs> Queue { get; set; }
|
|
|
|
public void Cancel()
|
|
{
|
|
|
|
}
|
|
|
|
public bool Dequeue(out TArgs? item)
|
|
{
|
|
return Queue.TryDequeue(out item);
|
|
}
|
|
public bool Enqueue(TArgs item)
|
|
{
|
|
if (IsDisposed)
|
|
return false;
|
|
|
|
Queue.Enqueue(item);
|
|
|
|
if (!Job.IsRunning)
|
|
Job.Run(Queue, CancellationToken);
|
|
|
|
return true;
|
|
}
|
|
|
|
private void OnCompleted(object? sender, EventArgs e)
|
|
{
|
|
if (sender is not DispatcherJob<TArgs> job)
|
|
return;
|
|
|
|
if (!Queue.IsEmpty)
|
|
{
|
|
job.Run(Queue, CancellationToken);
|
|
return;
|
|
}
|
|
|
|
Completed?.Invoke(this, EventArgs.Empty);
|
|
}
|
|
|
|
public bool Enqueue(string queue, TArgs args)
|
|
{
|
|
return Dispatcher.Enqueue(queue, args);
|
|
}
|
|
|
|
private void Dispose(bool disposing)
|
|
{
|
|
if (!IsDisposed)
|
|
{
|
|
if (disposing)
|
|
{
|
|
if (Job is not null)
|
|
{
|
|
Job.Dispose();
|
|
Job = null;
|
|
}
|
|
}
|
|
|
|
IsDisposed = true;
|
|
}
|
|
}
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
}
|