Getting Started
Architecture
NServiceBus
Transports
Persistence
ServiceInsight
ServicePulse
ServiceControl
Monitoring
Samples

Sender-Side Distribution

Component: MSMQ Transport
NuGet Package: NServiceBus (7.x)
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:

routingSettings.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 = routingSettings.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.

Related Articles