rebus-org / Rebus

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

Question about in-memory transport #599

Closed ShiroYacha closed 7 years ago

ShiroYacha commented 7 years ago

Hi, I have a question about the usage of in-memory transport. I am working on a project where we decide to implement a pub/sub architecture. There are many pub/sub modules that can be either packaged in the same binary (centralized) or in multiple binaries (distributed, same or diff network).

In order to maintain the flexibility of the design, we design that all modules use rebus to pub/sub. For the centralized use-case, is it a good idea to use In-Memory transport with the same InMem network so that in the future if we want to repackage some modules to the distributed system? In the documentation, it seems that in-memory is generally used for unit-testing. I have checked the implementation a bit but can't decide if using it for internal "pub/sub" is a good idea.

Best, Min

mookid8000 commented 7 years ago

If you are asking whether the in-mem transport is robust and fast enough to be used by Rebus as an in-process message bus, then the answer is definitely yes 😄

And you are absolutely right that doing that will provide a great deal of flexibility, because it can then be trivial to move your solution from a single-process model to distributed model (assuming of course that you do not do anything else that prohibits that).

k2ibegin commented 4 years ago

does Rebus support in memory transport mechanism like masstransit ?

mookid8000 commented 4 years ago

Yes 🙂

Check out the wiki page about transports for general information about transports.

Since the pattern is to just go

Configure.With(...)
    .Transport(t => t.Use???)
    .Start();

and the in-mem transport is built into the Rebus core DLL, you can simply go

Configure.With(...)
    .Transport(t => t.UseInMemoryTransport(...))
    .Start();

without any additional imports. 😁

The first argument to UseInMemoryTransport is an InMemNetwork, which you must then share with all of the Rebus instances that you want to enable communication between.

k2ibegin commented 4 years ago

that is great !! I have two more questions, as I am trying to evaluate if we should go ahead with Rebus OR go with custom implementation.

  1. Regarding the correlation IDs mechanisms using rebus. Does the correlation IDs work fine also with non http based services, such as workers ? I also had a look at this library but it feels like very ASP Net core specific.

  2. Also is it fine if a bunch of Microservices use Rebus for event bus implementation, but then other bunch of microservices (with different bounded contexts and domains) use Rebus too, however, i believe it is like two different instances of Rebus running at the same time ? Is this use case viable with Rebus ?

Thank you

mookid8000 commented 4 years ago

1) Rebus' correlation ID mechanism does not connect with anything else by itself – it just ensures that correlation IDs flow from Rebus handlers to all outgoing messages.

You might want to take a look at @skwasjer 's Rebus.Correlate, which appears to allow for correlation IDs to flow across HTTP as well.

2) I'm not sure I understand the question.... surely, you can run as many Rebus instances as you like 🙂

k2ibegin commented 4 years ago

Thanks a lot for your quick answers. So it means that if correlation ID is going out from the handlers to all outgoing messages, so i can have these IDs logged into different microservices logs and have some smart tooling like kafka to consolidate/follow up my business transaction across these services right ?

A few more questions I have

1) Does current Rebus implementation supports .Net Standard 2.1/.Net core 3+ 2) For rabbitMq I can create the routing keys based on class (event) types ? e.g. If i have an event of type IEmail, then I would like to build a routing key based on namespace and class combination, e.g. .Email. using reflection. Does Rebus supports such mechanisms ?

Thank you

mookid8000 commented 4 years ago

(1) Yes 🙂

(2) Rebus basically has two ways of sending messages: await bus.Send(..) and await bus.Publish(..).

When you await bus.Send(yourMessage), the message will be sent directly to the queue configured to be the owner:

Configure.With(...)
    .(...)
    .Routing(r => r.TypeBased().Map<YourMessage>("some-queue"))
    .Start();

When you await bus.Publish(yourEvent), the event will be published to a topic named after the type, e.g. YourAssembly.YourNamespace.YourEvent, YourAssembly.

This way, anyone who subscribed by calling await bus.Subscribe<YourEvent>() (thus binding their input queues to the topic YourAssembly.YourNamespace.YourEvent, YourAssembly) will receive the event.

k2ibegin commented 4 years ago

Great thank you for your quick answer.

Is it possible to use RabbitMQ via ConnectionFactory instead of Connection URL via Rebus ? . e.g. we have some instance of rabbitmq running in production we need to reuse the configuration that is already set for custom event bus library. However, I am exploring Rebus and was wondering if instead of using ConnectionString in UseRabbitMq , I can use something like ConnectionFactory in the link ?

I have my exchange, host, username, password etc defined in app settings file. e.g.

"RabbitMQ": { "HostName": "mybroker-service", "Port": 1234, "UserName": "test", "Password": "test", "Exchange": { "Name": "my.exchange", "Type": "topic", "Durable": "true", "AutoDelete": "false", "Queues": [ { "Durable": "true", "Exclusive": "false", "AutoDelete": "false", "RoutingKey": "#.iactionoccured.*", "Name": "actionworker" }, { "Durable": "true", "Exclusive": "false", "AutoDelete": "false", "RoutingKey": "#.iinfoupdated", "Name": "informationworker" } ] } }

and then workers can create those queues on the fly.

How can I inject this configuration while using Rebus with Rabbit MQ ?

mookid8000 commented 4 years ago

While it might be a little bit wonky, it's actually possible, because the .UseRabbitMq(..) builder has the ability to execute this customizer callback:

Configure.With(...)
    .Transport(t => t.UseRabbitMq(...)
        .CustomizeConnectionFactory(conn => conn))
    .(...)
    .Start();

where conn above is the connection factory. It's even possible to return a completely new instance, if you want.