Skip to main content

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 SendFifoAsync lanç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ísticaDetalhe
Fire-and-forgetTask.Run — caller retorna imediatamente
I/O dentro do backgroundawait dentro do Task.Run — não é discard _ =
Falha silenciosa para o callercatch loga, não propaga
Logs em inglêsConvenção dotnet-skill
FIFOGetQueueUrlFifo + 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

AspectoLogQueueService (Checkout)Cart atual
Fire-and-forgetTask.Run + await interno_ = SendEvent(evt) / _ = SendFifoAsync
Log de erroLogError no catchAusente
Checagem queue URLImplícita no awaitDescartada
Centralização1 serviço, N callers3 locais (handler + 2 local functions)
Cache URLDireto no IMessageBusServiceMessageBusServiceCachedDecorator (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.