Uma das mudanças mais significativas na versão 10 do Brighter envolve uma reformulação completa da implementação do padrão "outbox". Neste artigo, explicarei as principais diferenças entre as versões 9 e 10, por que essas mudanças foram necessárias e fornecerei um guia claro sobre como configurar o novo padrão "outbox" com PostgreSQL.
O que é o padrão outbox?
O padrão "outbox" é uma técnica crítica em sistemas distribuídos que garante a entrega confiável de mensagens enquanto mantém a consistência dos dados. Em vez de publicar mensagens diretamente em um sistema de mensageria, os aplicativos armazenam as mensagens em uma tabela de banco de dados (a "outbox"). Um processo em segundo plano separado (o "sweeper") então entrega essas mensagens de forma confiável ao sistema de mensageria.
Requisitos
- .NET 8 ou superior
- Um projeto .NET com estes pacotes NuGet
- Paramore.Brighter.Outbox.Hosting 10.0.0-preview.8
- Fornece a infraestrutura fundamental para implementar o padrão "outbox" em aplicações Brighter
- Paramore.Brighter.Outbox.PostgreSql 10.0.0-preview.8
- Implementa o armazenamento do "outbox" especificamente para bancos de dados PostgreSQL
- Paramore.Brighter.MessagingGateway.RMQ.Async 10.0.0-preview.8
- Fornece recursos de mensageria RabbitMQ assíncrona
- Paramore.Brighter.ServiceActivator.Extensions.DependencyInjection 10.0.0-preview.8
- Integra o Brighter com a estrutura de Injeção de Dependência da Microsoft
- Paramore.Brighter.ServiceActivator.Extensions.Hosting 10.0.0-preview.8
- Habilita a integração com a infraestrutura de Host Genérico da Microsoft
- Serilog.AspNetCore 9.0.0
- Fornece recursos de logging estruturado para aplicações ASP.NET Core
Recapitulação sobre o Brighter
Antes de continuar falando sobre a configuração do "outbox" com Postgres, vamos recapitular o que já sabemos sobre o Brighter.
Request (Command/Event)
Defina mensagens usando IRequest
:
public class OrderPlaced() : Event(Id.Random())
{
public string OrderId { get; set; } = string.Empty;
public decimal Value { get; set; }
}
-
Commands: Operações para um único destinatário (ex:
SendEmail
). -
Events: Notificações de broadcast (ex:
OrderShipped
).
Message Mapper (Opcional)
Traduz entre mensagens do Brighter e seus objetos de aplicação, por padrão o Brighter usará um Serializador JSON
public class OrderPlacedMapper : IAmAMessageMapper<OrderPlaced>, IAmAMessageMapperAsync<OrderPlaced>
{ ... }
Request Handler
Processa mensagens recebidas:
public class OrderPlaceHandler(ILogger<OrderPlaceHandler> logger) : RequestHandler<OrderPlaced>
{
public override Greeting Handle(Greeting command)
{
logger.LogInformation("{OrderId} placed with value {OrderValue}", command.OrderId, command.Value);
return base.Handle(command);
}
}
Como usar o outbox no Brighter
Antes de configurar o "outbox", é importante entender como interagir com ele
Publicando Mensagens Através do Outbox
O Brighter fornece o método DepositPostAsync
para armazenar mensagens no "outbox"
await commandProcessor.DepositPostAsync(
new OrderPlaced { OrderId = "ORD-123", Value = 99.99m },
cancellationToken: cancellationToken);
Configuração do outbox com PostgreSQL
1. Garanta que a tabela exista
O primeiro passo é criar a tabela do "outbox" em seu banco de dados PostgreSQL. Observe que o Brighter não gerenciará esta tabela para você - você é responsável por criá-la e adicionar os índices necessários:
CREATE TABLE IF NOT EXISTS "outboxmessages"
(
Id bigserial PRIMARY KEY, -- optional value you can make the MessageId as PK if you want
MessageId character varying(255) UNIQUE NOT NULL,
Topic character varying(255) NULL,
MessageType character varying(32) NULL,
Timestamp timestamptz NULL,
CorrelationId character varying(255) NULL,
ReplyTo character varying(255) NULL,
ContentType character varying(128) NULL,
PartitionKey character varying(128) NULL,
WorkflowId character varying(255) NULL,
JobId character varying(255) NULL,
Dispatched timestamptz NULL,
HeaderBag text NULL,
Body text NULL, -- It can be a blob
Source character varying (255) NULL,
Type character varying (255) NULL,
DataSchema character varying (255) NULL,
Subject character varying (255) NULL,
TraceParent character varying (255) NULL,
TraceState character varying (255) NULL,
Baggage text NULL
);
2. Configuração do outbox
Configure o "outbox" em sua configuração de injeção de dependência:
var conn = new RelationalDatabaseConfiguration(connectionString, "brightertests", "outboxmessages");
services
.AddSingleton<IAmARelationalDatabaseConfiguration>(conn)
.AddConsumers(opt => { ... }) // Or AddBrighter
.AddProducers(opt =>
{
opt.ConnectionProvider = typeof(PostgreSqlUnitOfWork);
opt.TransactionProvider = typeof(PostgreSqlUnitOfWork);
opt.Outbox = new PostgreSqlOutbox(outbox);
...
})
3. Configurar o Sweeper
O Brighter Sweeper é responsável por enviar as mensagens do "outbox" para o gateway de mensageria. Configure-o com tamanhos de lote e outras propriedades apropriadas:
services
.AddSingleton<IAmARelationalDatabaseConfiguration>(conn)
.AddConsumers(opt => { ... }) // Or AddBrighter
.UseOutboxSweeper(opt => { opt.BatchSize = 10; })
Observação: Se estiver executando em um ambiente multi-máquina, certifique-se de que apenas uma instância execute o "sweeper" ou configure o bloqueio distribuído (distributed lock) no Brighter para evitar entrega duplicada de mensagens.
4. Configurar o Arquivamento do Outbox
Se estiver executando em um ambiente multi-máquina, certifique-se de que apenas uma instância execute o "sweeper" ou implemente bloqueio distribuído para evitar entrega duplicada de mensagens.
services
.AddSingleton<IAmARelationalDatabaseConfiguration>(conn)
.AddConsumers(opt => { ... }) // Or AddBrighter
.UseOutboxArchiver<DbTransaction>(new NullOutboxArchiveProvider(),
opt => opt.MinimumAge = TimeSpan.FromMinutes(1));
Principais Diferenças Entre Brighter V9 e V10
Outbox como Singleton
Na Brighter V10, o "outbox" é implementado como um serviço singleton, o que significa:
- Publicação atômica de mensagens (onde várias mensagens ou todas são bem-sucedidas ou todas falham) requer uma abordagem diferente
- Se a publicação atômica em várias mensagens for crítica para seu aplicativo, considere abrir uma discussão no repositório GitHub do Brighter
Na Brighter V10, o "outbox" é um singleton, portanto, agora não é possível ter uma transação compartilhada (talvez exista uma solução alternativa que eu não encontrei), tornando impossível ter uma publicação atômica de mensagens, como se algo falhar, nenhuma mensagem seja enviada. Se você sentir que isso é um problema em seu aplicativo, abra uma discussão/issue no GitHub do Brighter.
Mudanças na Configuração do Banco de Dados
O construtor RelationalDatabaseConfiguration
agora usa:
- Segundo parâmetro:
databaseName
(anteriormente era o nome da tabela do outbox) - Essa mudança foi necessária para suportar telemetria aprimorada
Mudanças na tabela do banco de dados
Analisando os dois esquemas de tabela, eis as mudanças significativas entre Brighter V9 e V10:
1. Mudanças nos Tipos de Dados
-
MessageId: Alterado de
UUID
paracharacter varying(255)
- Fornece mais flexibilidade na identificação da mensagem
- Permite diferentes formatos de ID de mensagem além de apenas UUIDs
-
CorrelationId: Alterado de
UUID
paracharacter varying(255)
- Suporta formatos mais variados de ID de correlação usados em diferentes sistemas
2. Novas Colunas na V10
A V10 introduz várias novas colunas que suportam recursos avançados de mensageria:
- PartitionKey: Habilita o particionamento de mensagens para melhor escalabilidade
- WorkflowId & JobId: Suporta nova funcionalidade de processamento de fluxo de trabalho e trabalhos
- Source & Type: Fornece melhor categorização e roteamento de eventos
- DataSchema: Permite especificar o esquema de payload para validação
- Subject: Habilita capacidades mais granulares de filtragem de mensagens
-
TraceParent, TraceState & Baggage: Suporte integrado para rastreamento distribuído
- Essencial para observabilidade em sistemas distribuídos complexos
- Integra com padrões modernos de rastreamento
Conclusão
A reformulação do "outbox" na Brighter V10 representa um passo significativo em direção à padronização e interoperabilidade em arquiteturas orientadas a eventos. Ao adotar a especificação Cloud Events, o Brighter permite integração perfeita entre sistemas heterogêneos - seja você trabalhando com RabbitMQ, Kafka ou outras tecnologias de mensageria.
Embora as mudanças exijam algum esforço de migração, elas posicionam seu aplicativo para melhor manutenibilidade a longo prazo e compatibilidade com ecossistemas nativos da nuvem. A adição do suporte a Cloud Events garante que seus eventos serão compreendidos por qualquer sistema que siga este padrão emergente.
Para um exemplo completo funcional, confira a implementação completa no GitHub. Se você encontrar desafios durante a migração, a comunidade Brighter é ativa e acolhedora no GitHub - não hesite em abrir uma issue ou discussão para obter assistência.
Top comments (0)