Monitor multi-schema SQL endpoints with the ServiceControl adapter

Component: ServiceControl Transport Adapter
NuGet Package ServiceControl.TransportAdapter (1.x)
Target NServiceBus Version: 6.x

This sample shows how to configure ServiceControl to monitor endpoints and retry messages when using SQL Server transport with endpoints using separate schemas for queues.

The purpose of the adapter is to isolate ServiceControl from the specifics of the physical deployment topology of the business endpoints (such as SQL Server multi-schema mode) which are not supported out-of-the-box by ServiceControl.

Prerequisistes

  1. Install ServiceControl.
  2. Create ServiceControl database on the local SQL Server instance.
  3. Using ServiceControl Management tool, set up ServiceControl to monitor endpoints using SQL Server transport:
  • Add a new ServiceControl instance:
  • Use Particular.ServiceControl.SQL as the instance name (ensure there is no other instance of SC running with the same name).
  • Use "User" account and provide credentials to allow for integrated authentication.
  • Specify Data Source=.\SqlExpress;Initial Catalog=ServiceControl;Integrated Security=True;Max Pool Size=100;Min Pool Size=10 as a connection string. ServiceControl Manager will automatically create queue tables in the database.
If other ServiceControl instances have been running on this machine, it's necessary to specify a non-default port number for API. Adjust ServicePulse settings accordingly to point to this location.
  1. Ensure the ServiceControl process is running before running the sample.
  2. Install ServicePulse.
In order to connect to a different SQL Server instance, ensure all database connection strings are updated in the sample.

Running the project

  1. Start the projects: Adapter, Sales and Shipping. Ensure the adapter starts first because on start-up it creates a queue that is used for heartbeats.
  2. Open ServicePulse (by default it's available at http://localhost:9090/#/dashboard) and select the Endpoints Overview. The Shipping endpoint should be visible in the Active Endpoints tab as it has the Heartbeats plugin installed.
  3. Go to the Sales console and press o to create an order.
  4. Notice the Shipping endpoint receives the OrderAccepted event from Sales and publishes OrderShipped event.
  5. Notice the Sales endpoint logs that it processed the OrderShipped event.
  6. Go to the Sales console and press f to simulate message processing failure.
  7. Press o to create another order. Notice the OrderShipped event fails processing in Sales and is moved to the error queue.
  8. Press f again to disable message processing failure simulation in Sales.
  9. Go to the Shipping console and press f to simulate message processing failure.
  10. Go back to Sales and press o to create yet another order. Notice the OrderAccepted event fails in Shipping and is moved to the error queue.
  11. Press f again to disable message processing failure simulation in Shipping.
  12. Open ServicePulse and select the Failed Messages view.
  13. Notice the existence of one failed message group with two messages. Open the group.
  14. One of the messages is OrderAccepted which failed in Shipping, the other is OrderShipped which failed in Sales.
  15. Press the "Retry all" button.
  16. Go to the Shipping console and verify that the OrderAccepted event has been successfully processed.
  17. Go to the Sales console and verify that both OrderShipped events have been successfully processed.
  18. Shut down the Shipping endpoint.
  19. Open ServicePulse and notice a red label next to the heart icon. Click on the that icon to open the Endpoints Overview. Notice that the Shipping is now displayed in the Inactive Endpoints tab.

Code walk-through

The following diagram shows the topology of the solution:

Topology diagram

The code base consists of four projects.

Shared

The Shared project contains the message contracts.

Sales and Shipping

The Sales and Shipping projects contain endpoints that simulate the execution of a business process. The process consists of two events: OrderAccepted published by Sales and subscribed by Shipping and OrderShipped published by Shipping and subscribed by Sales.

The Sales and Shipping endpoints use separate schemas within the same database. The configuration of the schemas differs slightly because the Sales endpoint uses NServiceBus 6 while Shipping uses NServiceBus 5. The following code shows the Version 6 configuration:

//Use custom schema shipping for this endpoint
transport.DefaultSchema("sales");

//Configure schemas for ServiceControl queues to point to adapter
transport.UseSchemaForQueue("audit", "adapter");
transport.UseSchemaForQueue("error", "adapter");
transport.UseSchemaForQueue("Particular.ServiceControl", "adapter");

//Configure schema for shipping endpoint so that the subscribe message is sent to the correct address
transport.UseSchemaForQueue(
    queueName: "Samples.ServiceControl.SqlServerTransportAdapter.Shipping",
    schema: "shipping");

And the following code shows similar configuration expressed using Version 5 APIs:

//Use custom schema shipping for this endpoint
transport.DefaultSchema("shipping");

transport.UseSpecificConnectionInformation(
    //Configure schema for sales endpoint so that the subscribe message is sent to the correct address
    EndpointConnectionInfo.For("Samples.ServiceControl.SqlServerTransportAdapter.Sales").UseSchema("sales"),
    //Configure schemas for ServiceControl queues to point to the adapter
    EndpointConnectionInfo.For("audit").UseSchema("adapter"),
    EndpointConnectionInfo.For("error").UseSchema("adapter"),
    EndpointConnectionInfo.For("Particular.ServiceControl").UseSchema("adapter")
);

Both snippets show how to map the ServiceControl queues to the adapter schema, how to configure the schema for the current endpoint and how to specify other endpoints' schemas.

The business endpoints include a message processing failure simulation mode (toggled by pressing f) which can be used to generate failed messages for demonstrating message retry functionality.

The Shipping endpoint has the Heartbeats plugin installed to enable uptime monitoring via ServicePulse.

Adapter

The Adapter project hosts the ServiceControl.TransportAdapter. The adapter has two sides: endpoint-facing and ServiceControl-facing. In this sample both use SQL Server transport:

var transportAdapterConfig = new TransportAdapterConfig<SqlServerTransport, SqlServerTransport>("ServiceControl.SqlServer.Adapter");

The following code configures the adapter to use a custom schema (adapter) within the shared database. It also maps the schema for the Shipping endpoint. Notice there is no need to map the schema for the Sales endpoint. This is because NServiceBus Version 5 and below did not include the schema name in the address.

transportAdapterConfig.CustomizeEndpointTransport(
    customization: transport =>
    {
        var connection = @"Data Source=.\SqlExpress;Initial Catalog=nservicebus;Integrated Security=True;Max Pool Size=100;Min Pool Size=10";
        transport.ConnectionString(connection);

        //Use custom schema
        transport.DefaultSchema("adapter");

        //Necassary to correctly route retried messages because
        //SQL Server transport 2.x did not include schema information in the address
        transport.UseSchemaForQueue(
            queueName: "Samples.ServiceControl.SqlServerTransportAdapter.Shipping",
            schema: "shipping");

        SqlHelper.EnsureDatabaseExists(connection);
        SqlHelper.CreateSchema(connection, "adapter");
    });

Starting from Version 6, the schema name is included in the address.

The following code configures the adapter to communicate with ServiceControl:

transportAdapterConfig.CustomizeServiceControlTransport(
    customization: transport =>
    {
        transport.ConnectionString(
            @"Data Source=.\SqlExpress;Initial Catalog=ServiceControl;Integrated Security=True;Max Pool Size=100;Min Pool Size=10");
    });

Because the ServiceControl has been installed under a non-default instance name (Particular.ServiceControl.SQL) the control queue name needs to be overridden in the adapter configuration:

transportAdapterConfig.ServiceControlSideControlQueue = "Particular.ServiceControl.SQL";

Related Articles


Last modified