Explanation for Exchanges created by NServiceBus with RabbitMQ - rabbitmq

Can anyone please explain why NServiceBus creates the above RabbitMQ Exchanges along with the expected exchanges based on Handler configuration?
Edit: No IEvent / IMessage / object Handler classes defined.
Using DefiningEventAs changes nothing (same exchanges and queues created).
conf.DefiningEventsAs(
t => t.Name.EndsWith("Event") && t.Namespace != null && t.Namespace.EndsWith("Events"))
.DefiningCommandsAs(
t => t.Name.EndsWith("Command") && t.Namespace != null && t.Namespace.EndsWith("Commands"))
.UnicastBus()
.ImpersonateSender(false);
Referenced assemblies:
NServiceBus 4.4.0.0
NServiceBus.Transports.RabbitMQ 1.1.0.0
RabbitMQ.Client 3.2.4.0
We downgraded from a later version (though not the latest, I can't recall which one right now) but nothing changed.

This behavior is by design, we setup all exchanges including IEvent and Object since there could be subscribers that subscribe to all events using a IHandleMessages<IEvent|object> message handler. There is no way for us to know if there are subscribers that has such handlers so therefor we set those exchanges up by default.
They should cause no harm if not used but if you want to get rid of them you canoverride this behavior by implementing your own routing topology, IRoutingTopology that ignores those types. You would then register with the transport using .UseRoutingTopology<MyRoutingTopology>()

Related

Why when publish message to RabbitMQ with MassTransit, sends to another endpoint with skipped?

Here comes my code on my publisher app (a netcore API).
services.AddMassTransit(masstransit =>
{
masstransit.UsingRabbitMq((context, cfg) =>
{
cfg.Host(new Uri("rabbitmq://srv-docker-dev-01"), "/", h =>
{
h.Username("guest");
h.Password("guest");
});
cfg.ReceiveEndpoint("implantacao", e =>
{
e.ConfigureConsumeTopology = false;
e.Bind<ClienteAlteradoEvento>();
});
});
});
Even before I create a consumer, my RabbitMQ shows a skipped queue.
And the message is delivered on this __skipped.
Can someone tell me what I'm doing wrong?
Just a few points:
My consumer will not have access to the event class of my producer.
I will have 2 queues which have to consume my API. I'll probably configure another receive endpoint.
I thought I should have only 1 exchange for each microservice. Like, all the events published by comercial microservice, should use the same exchange, but MassTransit is creating one exchange each type. Is that correct?
Any thoughs and ideas, will be welcome. I'm just learning about RabbitMQ.
EDIT
Microservice A: Have endpoints to receive user input data of customers. Users send data like names, contracts, and anything else (many different types of data can be changed on different endpoints). Every time a customer is updated, this API should publish messages to update other microservices too. Lets say we have at least 3 different events: CustomerDataUpdatedEvent, CustomerAddressUpdatedEvent, CustomerContractsUpdatedEvent.
Microservice B: Want to consume the updates from costumer published by Microservice A. We don't have access to CustomerDataUpdatedEvent, CustomerAddressUpdatedEvent, CustomerContractsUpdatedEvent classes. We should build our class type on its side.
Microservice C: Want to consume the updates from costumer published by Microservice A. We don't have access to CustomerDataUpdatedEvent, CustomerAddressUpdatedEvent, CustomerContractsUpdatedEvent classes. We should build our class type on its side.
Neither B or C have access to class type on microservice A.
Is that possible? Does it makes sense?
Thanks
You are configuring a receive endpoint without any consumers on it. So any message produced that arrives on the queue will just be copied to the _skipped queue.
I'd suggest reading some documentation to get the feel for how messages, consumers, and endpoints are configured.
I wouldn't suggest using a single exchange (or even a single queue) for all the messages in a service, but since you're just learning I don't really know what else to suggest without details.
It is not recommended by Chris Patterson here, you could use RabbitMQ.Client. but it is not impossible.
In this documentation there are two ways to better understand:
Using ISendEndpoint Send<T>(...)
var endpoint = await busControl.GetSendEndpoint(new Uri("exchange:my-exchange"));
await endpoint.Send(new {});
Using IBus Publish<T>(...)
var bus = Bus.Factory.CreateUsingRabbitMq((cfgBus) =>
{
cfgBus.Host(host: eventbusoptions.Host);
// Remove default wrapper message
cfgBus.ClearSerialization();
cfgBus.UseRawJsonSerializer();
// Set exchange name
cfgBus.Message<SubmitOrder>(top =>
{
top.SetEntityName(eventbusoptions.ExchangeName);
});
// Configurations per Publish
cfgBus.Publish<SubmitOrder>(top =>
{
top.ExchangeType = eventbusoptions.ExchangeType;
top.Durable = false;
top.BindQueue(eventbusoptions.ExchangeName, eventbusoptions.QueueName, bind =>
{
bind.RoutingKey = eventbusoptions.RoutingKey;
bind.ExchangeType = eventbusoptions.ExchangeType;
bind.Durable = false;
});
});
});
await _bus.Publish<SubmitOrder>(order, context => context.SetRoutingKey(_eventBusOptions.RoutingKey));
I just realize MassTransit isn't what I'm looking for right now.
I read about RabbitMQ and people told me MassTransit should be a nice approach but I disagree. Maybe for some scenarios it would be perfect, but when you can't have the same type on both projects, it's a pain.
The "exchanges must be type" isn't flexible enough.
The problem of my question is the answer gave by Chris. But Mass will not do what I want. His answer is right, btw.

NServiceBus: Unable to set the value for key: NServiceBus.Transport.ConnectionString

My application I'm working on uses NServiceBus for a messaging bus for some operations. In my AppStartup, I'm trying to configure NServiceBus to use a custom Unicast config, which is running successfully it appears. However, when I call my Configure with this code:
ObjectFactory.Configure(configure =>
configure.For<IBus>().Use(
Configure
.With()
.StructureMapBuilder(ObjectFactory.Container)
.UseTransport<Msmq>()
.UnicastBus()
.SendOnly()
)
);
I get this exception:
Unable to set the value for key:
NServiceBus.Transport.ConnectionString. The settings has been locked
for modifications. Please move any configuration code earlier in the
configuration pipeline
Here's the stack trace for the exception (confidential parts omitted):
at NServiceBus.Settings.SettingsHolder.EnsureWriteEnabled(String key) in c:\BuildAgent\work\31f8c64a6e8a2d7c\src\NServiceBus.Core\Settings\SettingsHolder.cs:line 174
at NServiceBus.Settings.SettingsHolder.Set(String key, Object value) in c:\BuildAgent\work\31f8c64a6e8a2d7c\src\NServiceBus.Core\Settings\SettingsHolder.cs:line 57
at NServiceBus.Transports.ConfigureTransport`1.Configure(Configure config) in c:\BuildAgent\work\31f8c64a6e8a2d7c\src\NServiceBus.Core\Transports\ConfigureTransport.cs:line 21
at NServiceBus.TransportReceiverConfig.UseTransport(Configure config, Type transportDefinitionType, String connectionStringName) in c:\BuildAgent\work\31f8c64a6e8a2d7c\src\NServiceBus.Core\Unicast\Transport\Config\TransportReceiverConfig.cs:line 55
at NServiceBus.TransportReceiverConfig.UseTransport[T](Configure config, String connectionStringName) in c:\BuildAgent\work\31f8c64a6e8a2d7c\src\NServiceBus.Core\Unicast\Transport\Config\TransportReceiverConfig.cs:line 22
at ...
at StructureMap.Container.Configure(Action`1 configure) in c:\BuildAgent\work\767273992e840853\src\StructureMap\Container.cs:line 325
at StructureMap.ObjectFactory.Configure(Action`1 configure) in c:\BuildAgent\work\767273992e840853\src\StructureMap\ObjectFactory.cs:line 386
To be clear: this is on the client side, not on the actual bus side of the NServiceBus. This setup is taking place to be able to send messages to the NServiceBus queue, which is working properly already with another application. I've also confirmed that this application is configured the same as the other application.
Any help I could get on this would be great :)
RESOLVED!
For reference: the Bus object was being instantiated in the IOC configuration, but then the IOC was trying to repeat the process. This led to multiple instances of the IBus object being instantiated, which confused IOC since an IOC object should only be instantiated once according to StructureMap. I resolved this by surrounding my code with a check to see if the IBus object had been instantiated by my IOC controller or not before running configuration functions.
I had the same problem. This helped for me.
Configure.With()
.AutofacBuilder(container)
.UseTransport<Msmq>()
.MsmqSubscriptionStorage();

How to set up Redis in custom namespace as cache and MQ on ServiceStack web application using Structuremap

I want to set up my application to use Redis as Cache for sessions etc as well as run my Message Queues.
My application is a ASP.net MVC website along with ServiceStack based Json service provider. What is the optimal way to configure?
I want to be able to pass an IMessageQueueClient into my service classes and controllers so that I can add tasks to the queue.
I'm getting somewhat lost over what scope to make what. My code is as follows:
//Redis Client Manager
var pooledClientManager = new PooledRedisClientManager(ConfigurationManager.AppSettings.Get("RedisServer"));
pooledClientManager.NamespacePrefix = "myApp-";
For<IRedisClientsManager>().Singleton().Use(x => pooledClientManager);
//Cache
For<ICacheClient>().Use(c => c.GetInstance<IRedisClientsManager>().GetCacheClient());
//MQ
MyApplication.MqService = new RedisMqServer(pooledClientManager);
For<IMessageQueueClient>().Singleton(). Use(
x => MyApplication.MqService.CreateMessageQueueClient());
For<IMessageService>().Singleton().Use(x=>MyApplication.MqService);
I then later on call MyApplication.MqService.RegisterHandler(etc etc);
This works but I'm not convinced I've got my scoping correct.
The Namespace prefix doesn't work, and I need this feature.
Thanks for your help with this!
The NamespacePrefix is only for internal data-structures maintained by the RedisClients and doesn't affect user-specified keys.

Making Backward-Compatible WCF Services

TLDR: How do I create WCF services that are backward compatible -- that is, when I deploy a new version of the service on the server-side, all the clients on the older versions can still use the service.
I'm creating a web service that will allow the client applications to fetch a listing of plugins. I will at least have one operation like FindPlugins(string nameOrDescription) which will, on the server, do a search and return a list of objects.
Unfortunately, I cannot guarantee that my clients will all be updated with each new release of my service; nay, I am sure that many of them will be trailing the latest version, and will have old versions -- how old, I cannot be sure, but I know they will be old :)
If I create a new service operation, change the schema, or make some sort of breaking operation on the server side, I'm done. I need to engineer backward compatibility at all times.
Here's one example. Say I return a list of Plugins, each which has a name and description, and I deploy v0.1 of my service. Then, I add a download link, and deploy that as v0.2 of my service.
Some options which I see are:
Force clients to update to the latest service (not feasible)
Break the service for old clients (not feasible)
Append a version number to each operation and only consume the version-specific operations (eg. FindPluginsV1, FindPluginsV2) -- doesn't seem practical with multiple operations
Provide a new service with each new version -- doesn't seem practical
WCF is backwards-compatible by default.
The following MSDN link contains a list of all the possible changes of a WCF contract and describes their effect on old clients:
WCF Essentials: Versioning Strategies
Most importantly, the following operations will not cause old clients to break:
Service contracts (methods)
Adding method parameters: The default value will be used when called from old clients.
Removing methods parameters: The values sent by old clients will be ignored silently.
Adding new methods: Obviously, old clients won't call them, since they don't know them.
Data contracts (custom classes for passing data)
Adding non-required properties.
Removing non-required properties.
Thus, unless you mark the new DownloadLink field as IsRequired (default is false), your change should be fine.
If you look at this article http://blogs.msdn.com/b/craigmcmurtry/archive/2006/07/23/676104.aspx
The first example the guy gives will satisfy your requirements. It has the benefit that existing clients will not break, and you can add as many new service operations as you want this way.
[ServiceContract]
public interface IMyServiceContract
{
[OperationContract(IsOneWay=true)]
public void MyMethod(MyDataContract input);
}
[ServiceContract]
public interface IMyAugmentedServiceContract: IMyServiceContract
{
[OperationContract(IsOneWay=true)]
public void MyNewMethod(MyOtherDataContract input);
}
The change your service implementation:
public class MyOriginalServiceType: IAugmentedServiceContract { }

How to handle only specific messages using NServiceBus Host

I have a seperate class library of messages. Each handler implementing IHandleMessages. I also have a seperate class library that uses the NServiceBus.Host to act as a message handling service. I know I can handle the ordering of messages but can I say which message handlers I want the host to handle? At the minute it seems that any reference to IHandleMessage will be handled by the host
You can custom initialize your endpoint and use the With(IEnumerable<Type> typesToScan) overload. You will need to include the NSB types as well. I would recommend splitting up the assembly into multiple assemblies and then use the With(IEnumberable assemblies) overload to simplify the process. You could still deploy all handlers, but just configure endpoints to use a specific set.
Why not just have one handler per NServiceBus host? Makes it nice and easy.