Pesquisa — LogQueueService (referência AllLogs)
Data: 2026-07-01
Fonte: Sem Título/coezzion-service-checkout/src/Checkout.Infraestructure/EventHandlers/LogQueueService.cs
Contexto: Requisitos US 195746 citam "mesmo conceito do AllLogs de Payments".
Por que esta referência
Task #196021 (serviço de histórico):
Serviço responsável pela persistência na tabela
CartRecommendationsHistory. Mesmo conceito do AllLogs de Payments.
Task #196022 RF-02 (publish no create):
WHEN
SendFifoAsynclançar exceção THEN o sistema SHALL logar o erro e retornar o context sem adicionar erros (fire-and-forget — falha de observabilidade não deve impactar a criação do carrinho)
Ou seja: não bloquear a resposta HTTP, mas logar falhas. O LogQueueService implementa exatamente isso.
Implementação de referência
public class LogQueueService(
ILogger<LogQueueService> logger,
IMessageBusService messageBusService) : ILogQueueService
{
public Task EnqueueAsync(LogQueueMessageEvent message)
{
return Task.Run(async () =>
{
try
{
var queue = await messageBusService.GetQueueUrlFifo(QueueTypes.AWS_SQS_LOG_QUEUE_EVENTS_FIFO);
await messageBusService.SendFifoAsync(queue, message);
if (logger.IsEnabled(LogLevel.Information))
logger.LogInformation("Mensagem enfileirada. Fila: {queue}. Mensagem: {message}.", ...);
}
catch (Exception ex)
{
logger.LogError("Erro ao tentar enfileirar mensage na fila {queue}. Message: {ex}", ...);
}
});
}
}
Características importantes
| Característica | Detalhe |
|---|---|
| Fire-and-forget | Task.Run — caller retorna imediatamente |
| I/O dentro do background | await dentro do Task.Run — não é discard _ = |
| Falha silenciosa para o caller | catch loga, não propaga |
| Logs em inglês | Convenção dotnet-skill |
| FIFO | GetQueueUrlFifo + SendFifoAsync |
Decorator — cross-cutting
public class LogQueueServiceDecorator<T>(T inner, ITransactionContext transactionContext) : ILogQueueService
{
public Task EnqueueAsync(LogQueueMessageEvent message)
{
if (string.IsNullOrWhiteSpace(message.TransactionId))
message.TransactionId = transactionContext?.TransactionId;
return inner.EnqueueAsync(message);
}
}
Para Cart, decorator não é necessário no primeiro momento — RecommendationsId já é o correlation id.
Comparação com implementação atual do Cart
| Aspecto | LogQueueService (Checkout) | Cart atual |
|---|---|---|
| Fire-and-forget | Task.Run + await interno | _ = SendEvent(evt) / _ = SendFifoAsync |
| Log de erro | LogError no catch | Ausente |
| Checagem queue URL | Implícita no await | Descartada |
| Centralização | 1 serviço, N callers | 3 locais (handler + 2 local functions) |
| Cache URL | Direto no IMessageBusService | MessageBusServiceCachedDecorator (melhor) |
O que o review flagou incorretamente
O review anterior classificou fire-and-forget como bug. Pelos requisitos RF-02, fire-and-forget é intencional para create-cart. O problema real é a forma: discard sem Task.Run estruturado e sem log.
Adaptação para CartRecommendationHistoryPublisher
public Task PublishAsync(CartRecommendationsEvent evt, Guid recommendationsId)
{
return Task.Run(async () =>
{
try
{
var queueUrl = await _messageBusService.GetQueueUrlFifo(
QueueTypes.AWS_SQS_CART_RECOMMENDATION_HISTORY_FIFO);
if (string.IsNullOrWhiteSpace(queueUrl))
{
_logger.LogError(
"Failed to resolve queue URL. Queue: {QueueName}, RecommendationsId: {RecommendationsId}",
QueueTypes.AWS_SQS_CART_RECOMMENDATION_HISTORY_FIFO,
recommendationsId);
return;
}
var sent = await _messageBusService.SendFifoAsync(
queueUrl, evt, messageGroupId: recommendationsId.ToString());
if (!sent)
{
_logger.LogError(
"Failed to enqueue recommendation history event. RecommendationsId: {RecommendationsId}, EventType: {EventType}",
recommendationsId, evt.EventType);
}
}
catch (Exception ex)
{
_logger.LogError(ex,
"Error enqueueing recommendation history event. RecommendationsId: {RecommendationsId}, EventType: {EventType}",
recommendationsId, evt.EventType);
}
});
}
Por que messageGroupId = recommendationsId.ToString()
ADR/task #196020 — fila FIFO correlaciona eventos da mesma venda. RecommendationsId é o session/correlation id gerado no BFF.
Uso nos handlers
// PublishRecommendationHistoryHandler — não await o Task.Run (fire-and-forget)
_ = _publisher.PublishCreateCartAsync(...);
// Ou simplesmente (retorna Task já em background):
_publisher.PublishCreateCartAsync(...);
Caller não faz await — alinhado a RF-02.