SendOnly mode with no local queue - nservicebus

In NServiceBus you can create a SendOnly bus which means that all it will do is send messages to another service. It seems to me that this should not require a local queue for the sending service at all, however i have been unable to configure this.
var bus = Configure.With()
.DefiningCommandsAs(t => typeof(MyNamespace.Messaging.Markers.ICommand).IsAssignableFrom(t))
.DefaultBuilder()
.XmlSerializer()
.MsmqTransport()
.UnicastBus()
.SendOnly();
gives the following exception:
No endpoint name could be generated, please specify your own
convention using Configure.DefineEndpointName(...)
While i can solve this issue by adding a .DefineEndpointName it seems like poor form to be creating a queue for this service as it will never actually be used.
Is there a way of avoiding needing to create a local queue for a send only bus, and if not why is this local queue required in this mode?

All endpoints needs a name regardless if they are send only or not. This has nothing to do with the creation of queues(yes the queue name == endpoint name). Add a define endpoint name and you'll see that no queue will be created. Also note that the sent messages will not contain a reply to address since that wouldn't make sense.

I believe that this is provide where the message came from. The sending queue is an intrinsic part of MSMQ. It allows for ack messages, supports the NServiceBus bus.Reply feature.
In this case is it seems unnecessary, but if we consider that SendOnly is trying to guide the developer towards using a particular messaging style. Considering that MSMQ which supports many styles of messaging, this isn't such an issue in my view.

Related

Mass Transit + Azure Service Bus: Consume some types of messages without creating their corresponding topic

As I have been able to verify, in MassTransit with Azure Service Bus, each type of object consumed by a "Consumer" generates a Topic for that type regardless of whether it is only consumed in a specific "receive endpoint" (queue). When sending a message of this type with the "Send()" method, the message is sent directly to the "receive endpoint" (queue) without going through the topic. If this same message is published with the "Publish()" method, it is published in the Topic, and is forwarded to the receive endpoint (queue) from the corresponding subscriber.
My application uses a CQRS pattern where the messages are divided into commands and events. Commands use the send-receive pattern and are therefore always dispatched in MassTransit with the "Send()" method. The events, however, are based on the publish-subscribe pattern, and therefore are always dispatched in MassTransit with the "Publish()" method. As a result, a large number of topics are created on the bus that are never used (one for each type of command), since the messages belonging to these topics are sent directly to the receiver's queue.
For all these reasons, the question I ask is whether it is possible to configure MassTransit so that it does not automatically create the topics of some types of messages consumed because they will only be sent using the "Send()" method? Does this make sense in MassTransit or is it not possible/recommended?
Thank you!
Regards
Edited 16/04/2021
After doing some testing, I edit this topic to clarify that the intention is to configure MassTransit so that it does not automatically create the topics of some types of messages consumed, all of them received on the same receive endpoint. That is, the intention is to configure (dynamically if possible, through the type of object) which types of messages consumed create a topic and which do not in the same receive endpoint. Let's imagine that we have a receive endpoint (a queue) associated with a service, and this service is capable of consuming both commands and events, since the commands are only dispatched through Send(), it is not necessary to create the topic for them, however the events that are dispatched via Publish(), they need their topic (and their subscribers) to exist in order to deliver the message and be consumed.
Thanks in advance
Yes, for a receive endpoint hosting a consumer that will only receive Sent messages, you can specify ConfigureConsumeTopology = false for that receive endpoint. You can do that via a ConsumerDefinition, or when configuring the receive endpoint directly.
UPDATE
It is also possible to disable topology configuration per message type using an attribute on the message contract:
[ConfigureConsumeTopology(false)]
public interface SomeCommand
{
}
This will prevent the topic/exchange from being created and bound to the receive endpoint.
While I can understand the desire to be "pure to the CQRS mantra" and only Send commands, I'd suggest you read this answer and take it into consideration before overburdening your developers with knowing every single endpoint in the system by name...

How to make Rebus play nice with a custom topic exchange in RabbitMQ?

Rebus has flexible system that allows me to specify different endpoints for different message types, either in web.config or by implementing a custom IDetermineMessageOwnership.
As far as I can tell, message ownership is represented simply by a string. Using the MSMQ transport, this string points to a queue to which the message is delivered. With RabbitMQ, the string is used as a topic for the message, which is then delivered to a generic exchange named "Rebus". Rebus is a nice fellow, so he also sets up a queue in the RabbitMQ server, using the same name, and makes a binding from topic to queue within the Rebus exchange.
My question is this: Is it possible to have Rebus not create queues and bindings, but still deliver the messages to an exchange with a relevant topic set for each message?
Declaring the queues and bindings manually will allow me to set up an awesome topic exchange, using bindings with wildcards and what not. Here is a nice illustration of a topic exchange with funky bindings, just to make my question look more sleek and sexy:
Sounds to me like you want to do something like this:
Configure.With(yourFavoriteContainer)
.Transport(t => t.UseRabbitMq(...)
.ManageSubscriptions()) //< BAM!!1
.(...)
which lets Rebus take advantage of the fact that Rebus' RabbitMqMessageQueue implements IMulticastTransport, which in turn turns handling of all things multicast over to Rabbit.
It's just important that all of your Rabbit-enabled Rebus endpoints agree on letting Rabbit ManageSubscriptions - otherwise, weird stuff might happen ;)
It means that
when you bus.Subscribe<SomeEvent>, you bind a topic with the type name to the subscriber's input queue - e.g. "SomeEvent.SomeNamespace" -> myInputQueue
publishers publish events on a topic that is the type name - e.g. "SomeEvent.SomeNamespace"
message ownership is disregarded when subscribing
Rabbit will do the heavy lifting when doing multicast (which is what Rabbit users are mostly doing)
If you require even more flexibility, you can even take responsibility of deciding the topic to publish to for each .NET type, like so:
Configure.With(yourFavoriteContainer)
.Transport(t => t.UseRabbitMq(...)
.ManageSubscriptions()
.AddEventNameResolver(type => DecideTopic(type))
.(...)
You can add multiple event name resolvers if you want - they will be run in sequence until one of them returns something that is not null.
Does it make sense?

Bus Configuration with Autofac: Issue with RabbitMQ vs Loopback?

For some reason I can not post to the masstransit google group, even though I joined, I am told that I do not have permission to post to this group. So I am going to post here...
Now for my problem:
I am using MassTransit v2.7.2, with AutoFac v2.6.3. I am trying to configure Autofac to scan an assembly and register my consumers; all types that implement the IConsumer interface. This seems to work.
I am using the MassTransit.AutofacIntegration assembly and the LoadFrom(...) extension method to register the consumers from the container with MassTransit when I configure the bus. Here is the code:
var builder = new ContainerBuilder();
builder
.RegisterAssemblyTypes(typeof (CreateElectionCommandHandler).Assembly)
.Where(type => type.Implements<IConsumer>())
.AsSelf();
var container = builder.Build();
var localBus = ServiceBusFactory.New(configurator =>
{
//configurator.ReceiveFrom("loopback://localhost/testqueue");
configurator.ReceiveFrom("rabbitmq://localhost/commandqueue");
configurator.UseRabbitMq();
configurator.Subscribe(sbc => sbc.LoadFrom(container));
});
Assert.IsTrue(container.IsRegistered<CreateElectionCommandHandler>());
Assert.IsTrue(container.IsRegistered<TerminateElectionCommandHandler>());
Assert.AreEqual(1, localBus.HasSubscription<CreateElection>().Count());
Assert.AreEqual(1, localBus.HasSubscription<TerminateElection>().Count());
If I run the above code using the loopback
configurator.ReceiveFrom("loopback://localhost/testqueue");
configuration (comment out the rabbitmq conifig), the test will pass.
If I comment out the "loopback" config and comment in the
configurator.ReceiveFrom("rabbitmq://localhost/commandqueue");
configurator.UseRabbitMq();
config, the test will fail. (Note: The rabbitmq queue is already up and running - I have been using it as part of my POC). Specifically, it will fail on the assertion:
Assert.AreEqual(1, localBus.HasSubscription<CreateElection>().Count());
Assert.AreEqual(1, localBus.HasSubscription<TerminateElection>().Count());
Can anybody help me understand what is going on here? I am new to MT so fully anticipating that I am missing something, or not configuring something correctly.
Am I correct to assume that if there are no message subscriptions registered, then the bus will not be able to deliver to any of my consumers (even though the consumers are registered)?
Any help much appreciated!
With RabbitMQ, subscriptions are not added to the outbound bus until a message is published. This is due to how the classes are inspected and outbound endpoints to the appropriate exchanges are created and added to the pipeline.
So yes, this test will fail with RabbitMQ, but it will in fact work properly when the message is published.
The HasSubscription() calls are really meant for verifying that consumers and such are properly configured using the loopback transport, and really just for vetting out things that are not really integration issues but just making sure the internal MassTransit code is working.
So, if you were to add a Publish() call of one of those types, and then call the HasSubscription() extension method, it would pass.
I would check to see if MassTransit creates an exchange the message types in question. Messages are sent to the exchange and all consumer queues are bound to the exchange. You can look at the Rabbit config to see if that's happened or not as well. And with no consumers registered, no messages will be delivered. Chris has been working on adding options to error is there's consumers so you can handle it in your code.
I would join the mailing list https://groups.google.com/forum/?fromgroups=#!forum/masstransit-discuss to get help. There's a lot more people that can ask the right questions to get you where you need to be.

Clarification of topology

I understand that Rebus is perfectly capable of transporting messages from point A to B (using MSMQ as the transport layer). To make things perfectly clear, is Rebus also capable of doing one-to-many messaging, i.e. messages sent from point A should end at both point B and C?
And if it is possible, how does it do it? I cannot see any centralised distribution site (a post-office), so I assume that the communication will consist of a channel from every endpoint to every other endpoint (so that in a network where a process has to communicate with 5 other endpoints, there will be 5 channels radiating out of this process). Can you confirm this assumption?
Yes, Rebus is indeed capable of publishing messages to virtually any number of subscribers. It's true that MSMQ (at least in its most basic mode of operation) is a simple point-to-point channel, which is why there's a layer on top in order to implement true pub/sub.
The way it works, is that each subscriber has an endpoint mapping pointing to the publisher, and then each subscriber goes
bus.Subsribe<SomethingInterestingHappened>();
which causes an internal SubscriptionMessage to be sent the the publisher. The publisher must then remember who subscribed to each given message type, typically by storing this information in an SQL Server. All this happens automatically, it just requires that you configure some kind of subscription storage.
And then, when the time comes to publish something, the publisher goes
bus.Publish(new SomethingInterestingHappened { ... });
which will make Rebus look up all the subscribers of the given message type. This may be 0, 1 or more, and then the event will be sent to each subscriber's input queue.
You can read more about these things in the Rebus docs on the page about routing.
To give you a hint on how subscribers and publishers might be configured, check this out - this is a subscriber:
Configure.With(...)
.Transport(t => t.UseMsmq....)
.MessageOwnership(t => t.FromRebusConfigurationSection())
(...)
which also has an endpoint mapping that maps a bunch of events to a specific publisher:
<endpoints>
<add messages="SomePublisher.Messages" endpoint="publisher_input_queue" />
</endpoint>
and then the publisher might look like this:
Configure.With(...)
.Transport(t => t.UseMsmq....)
.Subscriptions(s => s.StoreInSqlServer(theConnectionString, "subscriptions")
.EnsureTableIsCreated())
(...)

What is the best way to route NServiceBus messages to specific clients?

Let's say I have a ClientRequestMessage message that contains a request for a specific Client. A web application will generate these requests and they need to be sent to the correct Client for handling. I can think of a few options for this.
I could have a single queue that all messages go to and specific client handlers check a property (like ClientId) to decide whether they care about it. This feels wrong on many levels to me though.
I could publish a message to all of the clients and they could decide whether or not they care about it during handling. This seems like too much traffic and wastes each client's time handling messages they shouldn't care about in the first place though.
I could have client specific queues that these messages get routed too. This one feels the best to me, but I am unsure of how to do it. I'd like to keep it simple and avoid client specific message types, but I am not sure how to tell NServiceBus "for client A send it to client A's queue and for client B send it to client B's queue".
So my question is, what is the best (most efficient? easiest to manage?) way to set this up? I am pretty sure I need to use the distributor, but not positive so thought I would ask.
BONUS QUESTION:
Let's say each client has multiple handlers. How can I make sure only one of them handles a given message? Would I need a distributor per client?
If what you really want is the solution that allows you to have just a single message where you can place a specific filter on the message based on clientId and only route the message to the client when it relates to them then I would use PServiceBus(pservicebus.codeplex.com). It will make it easier for you specific a set of subscriptions for each of your client where their messages are all filtered by clientId into a specific queue or what transport you have available. The below example shows filtering a ChatTopic by the UserName Property and the subscriber only receives the message at the specified transport when the message been published UserName property is not TJ. You are also allowed to use complex filter where you do thing such as GreaterThan("MyComplexProperty.Blah.ID", 5)
Subscriber.New("MyUserName").Durable(false)
.SubscribeTo(Topic.Select<ChatTopic>().NotEqual("UserName", "TJ"))
.AddTransport("Tcp",
Transport.New<TcpTransport>(
transport => {
transport.Format = TransportFormat.Json;
transport.IPAddress = "127.0.0.1";
transport.Port = port;
}), "ChatTopic")
.Save();
You can tell NSB where to put messages by using the MessageEndpointMappings configuration section. You can map a specific message type or a whole assembly to a queue. If you don't want to create specific message types and map them, then I would recommend the publish approach. The overhead of removing a message from the queue is pretty minimal.
If your "client" has many instances of NSB to pick up messages then you will need to use a Distributor. Check out the distributed Pub/Sub documentation.