I'm trying to create an worker service that polls database every few seconds for emails. Emails are passed to a priorityQueue and from there sent via Rest API to external provider. I would like to also implement some kind of limit on number of threads used by queue.
So here is my ExecuteAsync from BackGroundService:
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{/*Poll email database*/
var emails = await _emailRepository.GetEmailsToSend();
foreach (var email in emails) /*Queue downloaded emails*/
_queue.QueueEmail(email);
await Task.Delay(_emailOptions.PollTime, stoppingToken);
}
}
And here is my BackgroundEmailQueue to which emails are given:
public class BackgroundEmailQueue : IBackgroundEmailQueue
{
private readonly ILogger<BackgroundEmailQueue> logger;
private readonly ConcurrentPriorityQueue<EmailToSend> queue;
private readonly SemaphoreSlim signal;
private event Action EmailQued;
public BackgroundEmailQueue(ILogger<BackgroundEmailQueue> logger)
{
this.queue = new ConcurrentPriorityQueue<EmailToSend>();
this.signal = new SemaphoreSlim(5, 5);
this.EmailQued += OnEmailQued;
this.logger = logger;
}
public void QueueEmail(EmailToSend email)
{
if (email == null)
return;
queue.Add(email);
EmailQued.Invoke();
}
private async void OnEmailQued()
{
await signal.WaitAsync();
var email = queue.Take();
await Task.Run(async () => { .... /*sending email*/ } );
signal.Release();
}
}
This solution works as intended
My problem is:
Was using the event to fire new thread good solution?
Is there a better way to do this?