0

I am wondering if anyone can help me I am trying to write a class which will create a task queue of tasks which runs without waiting for the result. I have a couple issues the first is I want to remove the completed tasks from the queue so that the task queue does not grow to large and when application shuts down it will clear/finish the task queue first.

public interface IBackgroundTaskQueue
{
    void QueueBackgroundWorkItem(Task? workItem, CancellationToken cancellationToken);

    Task<Task?> DequeueAsync(
        CancellationToken cancellationToken);
}


public class BackgroundTaskQueue : IBackgroundTaskQueue
{
    private readonly ConcurrentQueue<Task?> _workItems = new();
    private readonly ILogger<BackgroundTaskQueue> _logger;
    private readonly SemaphoreSlim _signal = new(0);

    public BackgroundTaskQueue(ILogger<BackgroundTaskQueue> logger, IHostApplicationLifetime lifetime)
    {
        _logger = logger;
        lifetime.ApplicationStopped.Register(OnStopping);
        lifetime.ApplicationStopping.Register(OnStopping);
    }

    public void QueueBackgroundWorkItem(Task? workItem, CancellationToken cancellationToken)
    {
        if (workItem is null or { IsCanceled: true })
            return;

        _workItems.Enqueue(workItem);

        _signal.Release();
    }

    private void OnStopping()
    {
        try
        {
            DequeueAsync(CancellationToken.None).GetAwaiter().GetResult();
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "An error has occurred whilst attempting to dequeue the background work que.");
        }

    }

    public async Task<Task?> DequeueAsync(CancellationToken cancellationToken)
    {
        try
        {
            await _signal.WaitAsync(cancellationToken);
            _workItems.TryDequeue(out var workItem);

            return workItem;
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "An error has occurred whilst attempting to dequeue the background work que.");
        }

        return null;
    }
}
Jimbo Jones
  • 983
  • 4
  • 13
  • 48
  • [This](https://stackoverflow.com/questions/15522900/how-to-safely-call-an-async-method-in-c-sharp-without-await) could have the answer you're looking for – McFlurry Jul 22 '22 at 14:10
  • What is the actual goal? A somewhat common pattern is to have some set of tasks that need exclusive access to some resource, and for that there is the [LimitedConcurrencyTaskScheduler](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskscheduler?view=net-6.0) that can provide such functionality. – JonasH Jul 22 '22 at 14:16
  • @JonasH to have a queue of low priority but not long running tasks to executed, to which can run in the background so you do not have to wait for the tasks to complete and speed up a response but these task are executed in a manged way so there is no flood of tasks – Jimbo Jones Jul 22 '22 at 14:24
  • What's the intended usage of the `QueueBackgroundWorkItem`, `OnStopping` and `DequeueAsync` methods? Who is going to call then, and what's the purpose of each method? – Theodor Zoulias Jul 22 '22 at 14:36
  • @TheodorZoulias IHostApplicationLifetime (in built, docs here https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.hosting.ihostapplicationlifetime?view=dotnet-plat-ext-6.0) from the docs, allows consumers to be notified of application lifetime events such as when the application host has performed a graceful shutdown. the purpose of BackgroundTaskQueue was to run a queue of tasks in a FIFO manner and not all at the same time. So I am trying to create a task queue which will run using FIFO gracefully and I am having issues trying to achieve this goal – Jimbo Jones Jul 22 '22 at 14:44
  • 1
    Sounds to me like you probably want a [durable queue](https://blog.stephencleary.com/2021/01/asynchronous-messaging-1-basic-distributed-architecture.html), if this is for offloading work from web requests. – Stephen Cleary Jul 22 '22 at 19:10

0 Answers0