This sample is only relevant for the MSMQ transport. The other transports scale out using the competing consumer pattern.
Sometimes a single endpoint for handling messages is not enough, so there is a need to scale out. The following sample demonstrates how to scale out existing MSMQ message processing by distributing messages on the sender side.
Code walk-through
There are several projects in the solution.
Server1 and Server2
These two projects are identical and show the scale out in action from within Visual Studio. In a real-world scenario, there would be a single server project that is deployed to multiple paths and/or machines.
Instance ID
The following snippet instructs NServiceBus to get the instance ID from the appSettings
configuration section:
var discriminator = ConfigurationManager.AppSettings["InstanceId"];
endpointConfiguration.MakeInstanceUniquelyAddressable(discriminator);
<appSettings>
<add key="InstanceId" value="instance1"/>
</appSettings>
Never hard-code instance IDs because they are mostly an operations concern, and operations staff should be able to modify them without the need to recompile the source code.
Handling code
public class DoSomethingHandler :
IHandleMessages<DoSomething>
{
static ILog log = LogManager.GetLogger<DoSomethingHandler>();
public Task Handle(DoSomething message, IMessageHandlerContext context)
{
log.Info($"Message {message.SequenceId} received.");
return Task.CompletedTask;
}
}
Messages
Contains message definitions shared by the server and the client.
Client
The client configures the logical routing:
routing.RouteToEndpoint(
messageType: typeof(DoSomething),
destination: "Samples.SenderSideScaleOut.Server");
In addition to the logical routing, the client also uses an instance mapping file to tell NServiceBus about the specific instances of the server. This is done as follows:
var instanceMappingFile = routing.InstanceMappingFile();
instanceMappingFile.FilePath("routes.xml");
<endpoints>
<endpoint name="Samples.SenderSideScaleOut.Server">
<!-- Scaled-out endpoint -->
<instance discriminator="instance1" />
<instance discriminator="instance2" />
</endpoint>
</endpoints>
Running the code
Start the solution with all the console applications (Server1
, Server2
, Client
) as startup applications.
In the Client
console, press enter a few times to generate messages. This results in both the Server1
and Server2
consoles processing the generated messages in an alternating fashion. This is because the messages are sent in a round-robin way to Server1
and Server2
by the client using the sender-side distribution feature.