Refactor email queue worker and interface cleanup

Removed `InitAsync` from `IOutgoingEmailQueue` to decouple RabbitMQ initialization from the interface. Replaced `AsyncIniteWorker` with the correctly named `AsyncInitWorker` in `DependencyInjection.cs` and introduced a new, improved implementation of `AsyncInitWorker`.

The new `AsyncInitWorker` class initializes the outgoing email queue consumer using an event-driven RabbitMQ approach, with enhanced logging and error handling. Removed the outdated `AsyncIniteWorker` class to streamline the codebase.

These changes improve code clarity, maintainability, and correctness.
This commit is contained in:
2026-07-24 12:30:36 +02:00
parent d91ed70001
commit 3cba69ec42
4 changed files with 33 additions and 47 deletions

View File

@@ -11,10 +11,4 @@ public interface IOutgoingEmailQueue
Task EnqueueAsync(OutgoingEmailEvent outgoingEmailEvent, CancellationToken cancellationToken = default); Task EnqueueAsync(OutgoingEmailEvent outgoingEmailEvent, CancellationToken cancellationToken = default);
Task<int> GetQueueDepthAsync(CancellationToken cancellationToken = default); Task<int> GetQueueDepthAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Initialize RabbitMQ connection, channel, exchanges, and queues asynchronously.
/// Called lazily on first use via EnsureInitializedAsync.
/// </summary>
Task InitAsync(CancellationToken cancellationToken = default);
} }

View File

@@ -44,7 +44,7 @@ public static class DependencyInjection
.SetApplicationName("EmailProfiler"); .SetApplicationName("EmailProfiler");
// Register Background Workers // Register Background Workers
services.AddHostedService<AsyncIniteWorker>(); services.AddHostedService<AsyncInitWorker>();
return services; return services;
} }

View File

@@ -0,0 +1,32 @@
using DigitalData.EmailProfiler.Application.Common.Interfaces;
using DigitalData.EmailProfiler.Infrastructure.Queue;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace DigitalData.EmailProfiler.Infrastructure.Services.Background;
/// <summary>
/// A hosted background service responsible for initializing the outgoing email queue consumer.
/// Leverages a push-based, event-driven RabbitMQ consumer to eliminate polling overhead.
/// Email account configuration is resolved exclusively from application settings; no database access is performed.
/// </summary>
public class AsyncInitWorker(IOutgoingEmailQueue EmailQueue, ILogger<AsyncInitWorker> Logger) : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
Logger.LogInformation("Outgoing email queue worker is starting. Initializing event-driven RabbitMQ consumer.");
try
{
// Initialize the RabbitMQ push-based consumer. This call is non-blocking;
// message processing is handled asynchronously via registered event callbacks.
if (EmailQueue is OutgoingEmailQueue outgoingEmailQueue)
await outgoingEmailQueue.InitAsync(stoppingToken);
}
catch (Exception ex)
{
Logger.LogError(ex, "A critical error occurred while initializing the outgoing email queue consumer. The worker cannot proceed.");
throw;
}
}
}

View File

@@ -1,40 +0,0 @@
using DigitalData.EmailProfiler.Application.Common.Interfaces;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace DigitalData.EmailProfiler.Infrastructure.Services.Background;
/// <summary>
/// Background worker that processes outgoing emails from RabbitMQ queue.
/// Uses event-driven RabbitMQ consumer (push-based) instead of polling.
/// NO database operations - email account configuration comes from appsettings.
/// </summary>
public class AsyncIniteWorker(
IOutgoingEmailQueue EmailQueue,
ILogger<AsyncIniteWorker> Logger) : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
Logger.LogInformation("EmailSenderWorker started (event-driven RabbitMQ consumer)");
try
{
// Start RabbitMQ consumer (event-driven, non-blocking)
await EmailQueue.InitAsync(stoppingToken);
// Keep worker alive until cancellation
// await Task.Delay(Timeout.Infinite, stoppingToken);
}
catch (OperationCanceledException)
{
Logger.LogInformation("EmailSenderWorker is stopping");
}
catch (Exception ex)
{
Logger.LogError(ex, "EmailSenderWorker failed to start");
throw;
}
// Logger.LogInformation("EmailSenderWorker stopped");
}
}