ServiceControl Transport Adapter

Project Hosting | Nuget: ServiceControl.TransportAdapter (Version: 1.x)
Target NServiceBus Version: 6.x

The ServiceControl Transport Adapter decouples ServiceControl from the specifics of business endpoints transport to support scenarios where the endpoints' transport uses physical routing features not compatible with ServiceControl or where endpoints use mixed transports and/or multiple instances of message broker.

Usage scenarios

The ServiceControl Transport Adapter can be useful in three scenarios:

Mixed transports

Some endpoints in the system use different transport than the rest of the system but should report to the same instance of ServiceControl. This can happen for various reasons like integration with external parties or requirement to use a specific transport feature in a subset of endpoints (e.g. MSMQ store-and-forward for occasionally connected endpoints).

In this case a transport adapter can be used for the subset of endpoints that use a different transport. This allows management of the whole system from a single instance of ServicePulse.

The following code shows the configuration of the Transport Adapter in a mixed transport scenario:

Edit
var transportAdapterConfig = 
    new TransportAdapterConfig<MyOtherTransport, MyTransport>("MyOtherTransport");

transportAdapterConfig.CustomizeEndpointTransport(
    customization: transportExtensions =>
    {
        transportExtensions.ConnectionString(OtherTransportConnectionString);
    });

transportAdapterConfig.CustomizeServiceControlTransport(
    customization: transportExtensions =>
    {
        transportExtensions.ConnectionString(ConnectionString);
    });

Advanced transport features

Some transports offer advanced features which are not supported by ServiceControl (e.g. RabbitMQ custom routing topologies).

In this case a transport adapter can be used to translate between the customized transport on one side and ServiceControl using the default transport settings on the other side.

The following code shows the configuration of the transport adapter in the advanced features scenario:

Edit
var transportAdapterConfig = new TransportAdapterConfig<MyTransport, MyTransport>("TransportAdapter")
{
    EndpointSideAuditQueue = "audit_in",
    EndpointSideErrorQueue = "error_in",
    ServiceControlSideControlQueue = "control_in"
};

transportAdapterConfig.CustomizeEndpointTransport(
    customization: transportExtensions =>
    {
        transportExtensions.ConnectionString(ConnectionString);
        transportExtensions.UseSpecificRouting();
    });

transportAdapterConfig.CustomizeServiceControlTransport(
    customization: transportExtensions =>
    {
        transportExtensions.ConnectionString(ConnectionString);
    });

In the snippet above UseSpecificRouting represents any advanced routing configuration applicable for a given transport that is not compatible with ServiceControl. Notice that this configuration is only applied to the endpoint-side transport.

Multiple instances of a message broker

In some very large systems a single instance of a message broker can't cope with all the traffic. Endpoints can be grouped around broker instances. ServiceControl, however, is limited to a single connection.

In this case a separate transport adapter is deployed for each instance of a broker (e.g. RabbitMQ instance, SQL Server instance or ASB/ASQ namespace) while ServiceControl connects to its own instance. The adapters forward messages between instances.

Following code shows the configuration of the Transport Adapter in the multi-instance scenario:

Edit
var transportAdapterConfigOne = new TransportAdapterConfig<MyTransport, MyTransport>("One");
transportAdapterConfigOne.CustomizeEndpointTransport(
    customization: transportExtensions =>
    {
        transportExtensions.ConnectionString(BrokerOneConnectionString);
    });
transportAdapterConfigOne.CustomizeServiceControlTransport(
    customization: transportExtensions =>
    {
        transportExtensions.ConnectionString(ScConnectionString);
    });

var transportAdapterConfigTwo = new TransportAdapterConfig<MyTransport, MyTransport>("Two");
transportAdapterConfigTwo.CustomizeEndpointTransport(
    customization: transportExtensions =>
    {
        transportExtensions.ConnectionString(BrokerTwoConnectionString);
    });
transportAdapterConfigTwo.CustomizeServiceControlTransport(
    customization: transportExtensions =>
    {
        transportExtensions.ConnectionString(ScConnectionString);
    });

Notice that both adapter configurations use the same connection string for the ServiceControl and a different connection string for the endpoint-side transport.

Some transports, such as SQL Server transport, offer a native multi-instance mode. This mode is considered an advanced routing feature and allows use of a single instance of the transport adapter even though there are multiple instances of the broker.

Queue configuration

The transport adapter allows configuration of the addresses of the forwarded queues: audit, error and control (input queue of ServiceControl). Both endpoint- and ServiceControl-side queues can be configured.

The default values are only suitable in cases where both sides of the adapter use different transports or at least different broker instances. In case the adapter runs on a single transport and instance, the queue names on one side need to be altered.

Audit queues

Default: audit

Edit
transportAdapterConfig.EndpointSideAuditQueue = "audit_in";
transportAdapterConfig.ServiceControlSideAuditQueue = "audit_out";

Error queues

Default: error

Edit
transportAdapterConfig.EndpointSideErrorQueue = "error_in";
transportAdapterConfig.ServiceControlSideErrorQueue = "error_out";

Control queues

Default: Particular.ServiceControl

Edit
transportAdapterConfig.EndpointSideControlQueue = "control_in";
transportAdapterConfig.ServiceControlSideControlQueue = "control_out";

Poison message queue

The poison message queue is a special queue which is used when messages cannot be received from the transport because they are corrupted (e.g. message headers are malformed).

Default: poison

Edit
transportAdapterConfig.PoisonMessageQueue = "poison_queue";

Such messages cannot be forwarded to the error queue because ServiceControl won't be able to receive them. During normal operations the NServiceBus system never generates such malformed messages. They can be a generated, for example, by a misbehaving integration component.

Failure handling

ServiceControl Transport Adapter uses different failure handling strategies for different types of messages.

Audits and errors

Audited and failed messages sent by the endpoints to audit and error queues are subject to a retry forever policy. This means that the adapter will retry forwarding such message to ServiceControl until it succeeds.

Control messages

Control messages, such as heartbeats and custom checks, are subject to a best effort policy which retries each message up to a configured number of times.

Edit
transportAdapterConfig.ControlForwardingImmediateRetries = 10;

If the adapter still cannot forward the message, it will be dropped.

Retrying failed messages

Transport Adapter will attempt to retry delivering failed messages selected for retry for the configured number of times. If messages processing still fails, the messages will be routed back to ServiceControl and will reappear in ServicePulse. Following API controls the maximum number of attempts to forward a retry message:

Edit
transportAdapterConfig.RetryForwardingImmediateRetries = 10;

Message duplication

ServiceControl Transport Adapter can operate in different consistency modes depending on the transport configuration on both sides. By default, the highest supported mode for the transport is used.

If both transports support the TransactionScope transaction mode the transport adapter guarantees not to introduce any duplicates while forwarding messages between the queues. This is very important for the endpoints that can't cope with duplicates and rely on the DTC to ensure exactly-once message delivery.

In case at least one of the transports does not support the TransactionScope mode or is explicitly configured to a lower mode, the transport adapter guarantees at-least-once message delivery. This means that the messages won't be lost during forwarding (with the exception of control messages, as described above) but duplicates may be introduced on any side.

Duplicates are not a problem for ServiceControl because its business logic is idempotent but the regular business endpoints need to either explicitly deal with duplicates or enable the Outbox feature.

Samples

Related Articles


Last modified