rebus-org / Rebus

:bus: Simple and lean service bus implementation for .NET
https://mookid.dk/category/rebus
Other
2.3k stars 358 forks source link

Distributing message to many handlers where each has own transaction #893

Closed dario-l closed 4 years ago

dario-l commented 4 years ago

Hi,

I was looking for some mechanism for sending some work into the background. :)

I've make simple durable queue where I can save message and later they are handled in another thread by worker. Messages are dispatched to appropriate handlers. My problem is that I want to run each handler in a separate transaction. It means that I should replicate one message for each handler.

I thought that Rebus can handle that situation in a breeze but I can't make it to happen.

Is it possible to Publish messages within one process and handle them in handlers in a separated transactions like I described above using Rebus? If yes how I should to configure it? I'm using SqlServer. I have no other infrastructure like Rabbit or something like that.

mookid8000 commented 4 years ago

I suggest you either

or

Both will allow you to perform whatever work you want to do as individual operations that can succeed/fail independently of eachother.

I hope that makes sense 🙂

dario-l commented 4 years ago

I'm using Autofac. That's my configuration code:

builder.RegisterRebus((configurer, context) => configurer
    .Logging(c => c.NLog())
    .Transport(c => c.UseSqlServer(new SqlServerTransportOptions(connectionString), "RebusInputQueue"))
    .Subscriptions(s => s.StoreInSqlServer(connectionString, "RebusSubscriptions", true))
    .Routing(c => c.TypeBased())
    .Options(o =>
    {
        o.SetNumberOfWorkers(2);
        o.SetMaxParallelism(2);
        o.HandleMessagesInsideTransactionScope(new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted });
        o.SimpleRetryStrategy("RebusInputQueueError");
}));

Subsciptions are added through scanning assemblies:

public static IContainer StartupRebus(this IContainer container, Assembly[] assemblies)
{
    container.Resolve<IBus>().SubscribeFrom(assemblies);
    return container;
}

How to define individual subscribers for each event message within one single (web) application? :)

dario-l commented 4 years ago

@mookid8000 Maybe I do not understand the basic concepts of Rebus?

I'm looking for information on SO where You respond.

Do I understand correctly that one instance of IBus should have only one input queue and that one instance is a one Subscriber to that queue?

mookid8000 commented 4 years ago

Do I understand correctly that one instance of IBus should have only one input queue and that one instance is a one Subscriber to that queue?

Yes, that's exactly how it works.

What you can do, if you want to host multiple Rebus instances in the same process, is this:

  1. Install the Microsoft.Extensions.Hosting NuGet package
  2. Add a background worker for each of your additional Rebus instances
  3. Implement the background worker as an independent component with its own IoC container(*)

This approach has the added benefit that your additional subscribers will be super-easy to pull out and host on their own some day.


(*) Its main body could look somewhat like this (in a class that inherits from BackgroundWorker):

var services = new ServiceCollection();

services.AddThis();
services.AddThat();
services.AddRebus(....);

using var provider = services.BuildServiceProvider();

provider.UseRebus();

while (!stoppingToken.IsCancellationRequested) 
{
    await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken));
}
dario-l commented 4 years ago

Now I understand. Thanks. :)

Looks like simple modification to my current solution give me expected functionality without big revolution. Especially that I'm still on framework 4.8 and nancyfx 🤮 + owin. 😜