Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Is it possible to use MassTransit transactional outbox with multiple db contexts?

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

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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!

>Solution :

No, it isn’t. The transactional outbox only works with the default bus on a single DbContext.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading