1 Cenário
Desenho e falha
Com o padrão ou sem ele. A escolha mostra o problema e o que queremos melhorar. Uma falha troca o roteiro inteiro.
Consistência · Intermediário
Grava a mudança de negócio e a intenção de publicar um evento na mesma transação local.
Os controles percorrem eventos já definidos. O relógio da tela só regula a velocidade visual. A sequência não depende de um Kafka real nem de temporizadores para decidir o resultado.
Ative uma falha para trocar o roteiro inteiro. A troca recomeça a execução, para que o estado mostrado continue correspondente ao cenário escolhido.
1 Cenário
Com o padrão ou sem ele. A escolha mostra o problema e o que queremos melhorar. Uma falha troca o roteiro inteiro.
2 Percurso
A trilha mostra cada etapa, inteira, na mesma tela. O relógio só muda a velocidade, não o resultado.
3 Agora
O texto ao lado do diagrama explica o evento que está na tela.
4 Registros
As tabelas provam o efeito: pedido, mensagem, cobrança ou ack.
2 Percurso
Aguardando o pedido
Cada etapa automática leva 1,6 s. Espaço inicia ou pausa. As setas mudam a etapa.
4 Registros
| Pedido | Cliente | Estado |
|---|---|---|
| Nenhuma linha | ||
| Mensagem | Tipo | Estado | Tentativas |
|---|---|---|---|
| Nenhuma linha | |||
| Evento | Resultado |
|---|---|
| Nenhuma linha | |
Limite do padrãoEsta é uma simulação no navegador. O Outbox registra a intenção de publicar. Ele não garante entrega exatamente uma vez, e o consumidor precisa tolerar uma mensagem repetida.
Um serviço precisa gravar uma mudança de negócio e avisar outros serviços. Se a gravação e a publicação são operações separadas, qualquer falha no meio deixa um dos lados sem o outro.
No pedido, isso aparece de dois jeitos. O commit pode acontecer e o evento se perder. Ou o broker pode aceitar OrderCreated e a transação local falhar, deixando um evento sem o pedido. Uma nova tentativa do POST ainda pode criar um segundo pedido.
Sem Outbox, gravar o pedido e publicar são operações separadas. No fluxo normal o commit vem primeiro. A falha do Kafka deixa o pedido sem evento. A outra ordem publica primeiro: se a transação falha depois, o evento fica sem o pedido.
Com Outbox, o serviço grava o pedido e a mensagem na mesma transação local. A API responde em seguida. Um worker publica as mensagens pendentes e marca o que já foi enviado.
Use o padrão quando perder o evento causa divergência de negócio e a publicação precisa ocorrer depois de um commit local bem-sucedido.
Os dois registros usam o mesmo contexto e a mesma transação do banco. O dispatcher abaixo é intencionalmente incompleto: falta a reserva atômica, o limite de tentativas e o tratamento da falha entre o ack e a atualização da Outbox.
// Fragmento ilustrativo. Orders e OutboxMessages usam o mesmo DbContext
// e a mesma transação do banco. Isto não é uma transação distribuída.
await using var transaction =
await dbContext.Database.BeginTransactionAsync(cancellationToken);
var order = Order.Create(request.CustomerId);
dbContext.Orders.Add(order);
dbContext.OutboxMessages.Add(
OutboxMessage.Create(
eventType: "OrderCreated",
payload: JsonSerializer.Serialize(new OrderCreated(order.Id))));
await dbContext.SaveChangesAsync(cancellationToken);
await transaction.CommitAsync(cancellationToken);
// Dispatcher simplificado de propósito.
// Esta versão não reserva a mensagem com atualização condicional,
// não limita tentativas e não trata a falha entre o ack do broker
// e a atualização da Outbox.
var pending = await dbContext.OutboxMessages
.Where(message => message.Status == OutboxStatus.Pending)
.OrderBy(message => message.OccurredAt)
.Take(20)
.ToListAsync(cancellationToken);
foreach (var message in pending)
{
await producer.ProduceAsync(
topic: "orders",
key: message.Id.ToString(),
payload: message.Payload,
cancellationToken);
message.MarkProcessed();
}
await dbContext.SaveChangesAsync(cancellationToken);
Responda com o que a simulação mostrou. Cada questão abre a própria resposta.
Resposta
Idempotência. A mesma mensagem pode ser publicada outra vez, porque o ack do broker e a atualização da Outbox não acontecem na mesma transação. O consumidor reconhece a cópia já aplicada e não repete o efeito.
Resposta
O evento existe e o pedido não. O consumidor pode aplicar um efeito para uma mudança que não foi confirmada. O rollback local não apaga a mensagem que o broker já aceitou.
Resposta
O pedido já existe e não há uma pendência durável para retomar a publicação. Um novo POST pode criar outro pedido. Tratar o erro como ausência de pedido esconde a gravação que já ocorreu.
Resposta
Não. Essa janela pode publicar a mensagem de novo. O Outbox registra a intenção e sobrevive à queda do broker. A entrega repetida continua possível.
Resposta
Para os dois serem confirmados ou revertidos juntos. Se a transação falha, não sobra pedido sem intenção de publicar, nem intenção sem o pedido.