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?
BlockingCollection? Perhaps Google forblockingcollection process in parallel?