Getting Started
Architecture
NServiceBus
Persistence
ServiceInsight
ServicePulse
ServiceControl
Monitoring
Samples

Physical routing with MSMQ

Component: MSMQ Transport
NuGet Package: NServiceBus.Transport.Msmq (2.x)
Target Version: NServiceBus 8.x

The MSMQ transport in NServiceBus is a distributed transport in which the MSMQ process runs on each machine, storing messages locally before being forwarded to other machines. In this model, each endpoint connects to the local MSMQ process and both the queue name and the hostname must be specified when addressing a different endpoint.

Scaling out

Because the MSMQ queues are not accessible from outside the machine they are hosted in, NServiceBus endpoints using the MSMQ transport are not able to use the competing consumers pattern to scale out with a single shared queue.

Sender-side distribution can be used to overcome this limitation.

Physical mapping

Mapping the logical destination to the physical address containing the queue and host names is the responsibility of physical routing.

The preferred way of configuring the physical routing is via the instance mapping file.

Instance mapping file

The instance mapping file is a simple XML file that has to be located either on a local hard drive or a network drive. When using MSMQ as the transport, NServiceBus will automatically look for an instance-mapping.xml file in AppDomain.BaseDirectory.

<endpoints>
  <endpoint name="Sales">
    <instance machine="VM-1"/>
  </endpoint>
  <endpoint name="Shipping">
    <instance machine="VM-2"/>
  </endpoint>
  <endpoint name="Billing">
    <instance machine="VM-3"/>
  </endpoint>
</endpoints>

The mapping file is processed before the endpoint starts up and then re-processed at regular intervals so the changes in the document are reflected in the behavior of NServiceBus automatically. If the document is not present in its configured location when endpoint starts up, NServiceBus will not search again for the file at runtime. If it is deleted when the endpoint is already running, it will continue to run normally with the last successfully read routes.

There are many different options to consider when deploying routing configuration.

  • Many endpoints can be configured to use one centralized mapping file on a network drive accessible by all, creating a single file that describes how messages flow across an entire system. Any given endpoint will not care if the file contains information for endpoints it does not need.
  • The mapping file can be kept in a centralized location and replicated out to many servers on demand, allowing each endpoint to read the file from a location on the local disk.
  • Each endpoint can keep its own instance mapping file containing only information for the endpoints it needs to know about, which can be deployed in the same directory as the endpoint binaries and only modified as part of a controlled deployment process.

The following default settings can be adjusted:

RefreshInterval

Specifies the interval between route data refresh attempts.

Default: 30 seconds

var routing = endpointConfiguration.UseTransport(new MsmqTransport());
var instanceMappingFile = routing.InstanceMappingFile();
var fileSettings = instanceMappingFile.FilePath(@"C:\instance-mapping.xml");
fileSettings.RefreshInterval(TimeSpan.FromSeconds(45));

File Path

Specifies the path and file name of the instance mapping file. This can be a relative or an absolute file path. Relative file paths are resolved from AppDomain.BaseDirectory.

Default: instance-mapping.xml

var routing = endpointConfiguration.UseTransport(new MsmqTransport());
var instanceMappingFile = routing.InstanceMappingFile();
instanceMappingFile.FilePath(@"C:\instance-mapping.xml");

Uri Path (Requires version 1.1+)

Specifies a URI path of the instance mapping file. Relative paths are assumed to be file paths.

var routing = endpointConfiguration.UseTransport(new MsmqTransport());
var instanceMappingFile = routing.InstanceMappingFile();
instanceMappingFile.Path(new Uri("http://myserver/instance-mapping.xml"));

When ServiceControl is installed on a different server

The instance mapping file will have no effect on the error, audit, metrics, and plugin queues, so if a ServiceControl instance is installed on a different machine than the endpoint the physical mapping must be specified during configuration using queuename@machinename addresses:

Configuring recoverability

endpointConfiguration.SendFailedMessagesTo("Error_Queue@machinename");

Configuring auditing

endpointConfiguration.AuditProcessedMessagesTo("Audit_Queue@machinename");

Configuring metrics

var metrics = endpointConfiguration.EnableMetrics();
metrics.SendMetricDataToServiceControl(
    serviceControlMetricsAddress: "ServiceControl_Metrics_Queue@machinename",
    interval: TimeSpan.FromMinutes(1),
    instanceId: "INSTANCE_ID_OPTIONAL");

Configuring heartbeats

endpointConfiguration.SendHeartbeatTo(
    serviceControlQueue: "ServiceControl_Queue@machinename",
    frequency: TimeSpan.FromSeconds(15),
    timeToLive: TimeSpan.FromSeconds(30));

Configuring custom checks

endpointConfiguration.ReportCustomChecksTo(
    serviceControlQueue: "ServiceControl_Queue@machinename",
    timeToLive: TimeSpan.FromSeconds(10));

Overriding physical routing

When overriding the default routing to a queue on a different server the machine name must also be provided:

var options = new SendOptions();
options.SetDestination("MyDestination@machinename");
options.RouteReplyTo("MyDestination@machinename");
await endpoint.Send(new MyMessage(), options);

Schema validation

Every time the instance mapping file is loaded, it is validated against a schema to ensure it is correct. In NServiceBus.Transport.Msmq version 1.0 this schema allows arbitrary attributes in the instance element. NServiceBus.Transport.Msmq version 1.1 introduced a stricter schema which checks to ensure that no unexpected attributes are present. This helps to discover common mistakes with the instance mapping file, such as misspelled attributes.

If the instance mapping file cannot be validated against the stricter schema, the endpoint logs a warning and falls back to the old schema validation mechanism.

The transport can be configured to throw an error if the instance mapping file fails the strict schema validation, rather than falling back:

var routing = endpointConfiguration.UseTransport(new MsmqTransport());
var instanceMappingFile = routing.InstanceMappingFile();
instanceMappingFile.EnforceStrictSchemaValidation();

Related Articles