in src/Relecloud.TicketRenderer/TicketRenderRequestMessageHandler.cs [14:88]
internal sealed class TicketRenderRequestMessageHandler(
ILogger<TicketRenderRequestMessageHandler> logger,
IOptions<MessageBusOptions> options,
IMessageBus messageBus,
ITicketRenderer ticketRenderer) : IHostedService, IAsyncDisposable
{
private IMessageProcessor? processor;
private IMessageSender<TicketRenderCompleteMessage>? sender;
public async Task StartAsync(CancellationToken cancellationToken)
{
logger.LogDebug("TicketRenderRequestHandler is starting");
if (options.Value.RenderRequestQueueName is null)
{
logger.LogWarning("No queue name was specified. TicketRenderRequestHandler will not start.");
return;
}
// If a queue/topic name was specified, use it to publish messages when tickets are rendered.
if (!string.IsNullOrEmpty(options.Value.RenderCompleteQueueName))
{
sender = messageBus.CreateMessageSender<TicketRenderCompleteMessage>(options.Value.RenderCompleteQueueName);
}
// Initialize the message processor to listen for ticket render requests.
processor = await messageBus.SubscribeAsync<TicketRenderRequestMessage>(
async (request, cancellationToken) =>
{
// Render the ticket image and get the path it was written to.
var outputPath = await ticketRenderer.RenderTicketAsync(request, cancellationToken);
// If a queue/topic name was specified, publish a message indicating that the ticket was rendered.
if (outputPath is not null && sender is not null)
{
await sender.PublishAsync(new TicketRenderCompleteMessage(Guid.NewGuid(), request.Ticket.Id, outputPath, DateTime.Now), cancellationToken);
}
},
null, // Error handling callback
options.Value.RenderRequestQueueName, // Queue to subscribe to.
cancellationToken);
}
public async Task StopAsync(CancellationToken cancellationToken)
{
logger.LogDebug("TicketRenderRequestHandler is stopping");
if (processor is not null)
{
await processor.StopAsync(cancellationToken);
}
if (sender is not null)
{
await sender.CloseAsync(cancellationToken);
}
}
// Cleanup IAsyncDisposable dependencies
// as per https://learn.microsoft.com/dotnet/standard/garbage-collection/implementing-disposeasync#sealed-alternative-async-dispose-pattern
public async ValueTask DisposeAsync()
{
if (processor is not null)
{
await processor.DisposeAsync();
processor = null;
}
if (sender is not null)
{
await sender.DisposeAsync();
sender = null;
}
}
}