ServiceControl and Multi-Instance Mode

Even though it is recommended that all SQL Server transport queue tables are stored in a single SQL Server catalog, it is possible to use ServiceControl to monitor multi-catalog and multi-instance deployments of the SQL Server transport. A requirement for such configurations is that all endpoints share error and audit queues and that these queues are stored in the same catalog as ServiceControl queues. Other queues used by individual endpoints may be stored in different SQL Server catalogs and instances. The following diagram shows an example system configuration:

ServiceControl configuration

Distributed transactions

Multi-instance deployment of the SQL Server transport requires that the Distributed Transaction Coordinator (DTC) be used by all endpoints. This is also required by ServiceControl to support retry of failed messages. The default configuration of ServiceControl disables support for distributed transactions and it must be enabled explicitly using the EnableDtc configuration setting:

<appSettings>
  <add key="ServiceControl/EnableDtc"
       value="True" />
</appSettings>
ServiceControl supports the DTC only for the SQL Server transport. The EnableDtc switch has no effect on other transports.

Multiple connection strings

The default SQL Server transport connection string used by ServiceControl must point at a SQL Server instance that stores error, audit, and ServiceControl queues. In order to support retry of failed messages, ServiceControl also has to be configured with connection strings for each individual endpoint:

<connectionStrings>
  <add name="NServiceBus/Transport"
       connectionString="Server=DbServerA;Database=ServiceControlDB;"/>
  <add name="NServiceBus/Transport/Billing"
       connectionString="Server=DbServerB;Database=BillingDB;"/>
  <add name="NServiceBus/Transport/Sales"
       connectionString="Server=DbServerC;Database=SalesDB;"/>
</connectionStrings>

Endpoint configuration

Each endpoint can use queues stored in any SQL Server instance except for shared error and audit queues, which need to be stored in an instance used by ServiceControl. This cannot be expressed in the configuration file but can be implemented using the pull mode API:

3.x NServiceBus.SqlServer
var transport = endpointConfiguration.UseTransport<SqlServerTransport>();
transport.EnableLegacyMultiInstanceMode(async transportAddress =>
{
    string connectionString;

    if (transportAddress == "error" ||
        transportAddress == "audit" ||
        transportAddress.StartsWith("Particular.ServiceControl"))
    {
        connectionString = "Server=DbServerA;Database=ServiceControlDB;";
    }
    else if (transportAddress == "Billing")
    {
        connectionString = "Server=DbServerB;Database=BillingDB;";
    }
    else if (transportAddress == "Sales")
    {
        connectionString = "Server=DbServerC;Database=SalesDB;";
    }
    else
    {
        throw new Exception($"Connection string not found for transport address {transportAddress}");
    }

    var connection = new SqlConnection(connectionString);
    await connection.OpenAsync()
        .ConfigureAwait(false);
    return connection;
});
2.1 NServiceBus.SqlServer
var transport = busConfiguration.UseTransport<SqlServerTransport>();
transport.UseSpecificConnectionInformation(transportAddress =>
{
    if (transportAddress == "error" ||
        transportAddress == "audit" ||
        transportAddress.StartsWith("Particular.ServiceControl"))
    {
        return ConnectionInfo.Create()
            .UseConnectionString("Server=DbServerA;Database=ServiceControlDB;");
    }
    if (transportAddress == "Billing")
    {
        return ConnectionInfo.Create()
            .UseConnectionString("Server=DbServerB;Database=BillingDB;");
    }
    if (transportAddress == "Sales")
    {
        return ConnectionInfo.Create()
            .UseConnectionString("Server=DbServerC;Database=SalesDB;");
    }
    throw new Exception($"Connection string not found for transport address {transportAddress}");
});

Last modified