I am trying to build a modular monolith application where each module is defined in its own class library project. I would like to utilize a single SQL Server 2019
database and create a separate db schema for each of the individual modules. I would like to also utilize the built-in MassTransit outbox pattern implementation. The thing is that I want to have the 3 auto-generated outbox tables in each database schema:
cards.InboxState
cards.OutboxState
cards.OutboxMessage
transactions.InboxState
transactions.OutboxState
transactions.OutboxMessage
This is my current MassTransit configuration:
builder.Services.AddMassTransit(x =>
{
var hostUri = builder.Configuration.GetValueOrThrow<string>("RABBITMQ_URI");
var username = builder.Configuration.GetValueOrThrow<string>("RABBITMQ_USERNAME");
var password = builder.Configuration.GetValueOrThrow<string>("RABBITMQ_PASSWORD");
x.AddConsumer<CreditCardCreatedByIssuerEventConsumer>();
x.AddConsumer<CreditCardRequestedEventConsumer>();
x.SetKebabCaseEndpointNameFormatter();
x.AddEntityFrameworkOutbox<CardsDbContext>(o =>
{
o.QueryDelay = TimeSpan.FromSeconds(3);
o.UseSqlServer();
o.UseBusOutbox();
});
x.AddEntityFrameworkOutbox<TransactionsDbContext>(o =>
{
o.QueryDelay = TimeSpan.FromSeconds(3);
o.UseSqlServer();
o.UseBusOutbox();
});
x.UsingRabbitMq((ctx, cfg) =>
{
cfg.Host(new Uri(hostUri), h =>
{
h.Username(username);
h.Password(password);
});
cfg.AutoStart = true;
cfg.ConfigureEndpoints(ctx);
});
});
I am currently getting the following error:
2024-03-15 18:59:17 fail: MassTransit.EntityFrameworkCoreIntegration.BusOutboxDeliveryService[0]
2024-03-15 18:59:17 ProcessMessageBatch faulted
2024-03-15 18:59:17 System.NullReferenceException: Object reference not set to an instance of an object.
2024-03-15 18:59:17 at MassTransit.Middleware.Outbox.BusOutboxNotification.WaitForDelivery(CancellationToken cancellationToken) in /_/src/MassTransit/Middleware/Outbox/BusOutboxNotification.cs:line 38
2024-03-15 18:59:17 at MassTransit.EntityFrameworkCoreIntegration.BusOutboxDeliveryService`1.ExecuteAsync(CancellationToken stoppingToken) in /_/src/Persistence/MassTransit.EntityFrameworkCoreIntegration/EntityFrameworkCoreIntegration/BusOutboxDeliveryService.cs:line 72
The thing is that everything works as expected once I remove one of the db context registrations:
builder.Services.AddMassTransit(x =>
{
var hostUri = builder.Configuration.GetValueOrThrow<string>("RABBITMQ_URI");
var username = builder.Configuration.GetValueOrThrow<string>("RABBITMQ_USERNAME");
var password = builder.Configuration.GetValueOrThrow<string>("RABBITMQ_PASSWORD");
x.AddConsumer<CreditCardCreatedByIssuerEventConsumer>();
x.AddConsumer<CreditCardRequestedEventConsumer>();
x.SetKebabCaseEndpointNameFormatter();
x.AddEntityFrameworkOutbox<CardsDbContext>(o =>
{
o.QueryDelay = TimeSpan.FromSeconds(3);
o.UseSqlServer();
o.UseBusOutbox();
});
x.UsingRabbitMq((ctx, cfg) =>
{
cfg.Host(new Uri(hostUri), h =>
{
h.Username(username);
h.Password(password);
});
cfg.AutoStart = true;
cfg.ConfigureEndpoints(ctx);
});
});
So the logical question is if this is even possible?
And if it isn't could you suggest some sort of a workaround to this?
Any help would be greatly appreciated! Thanks!
No, it isn't. The transactional outbox only works with the default bus on a single
DbContext
.