SQL Server

Use Nimbus with SQL Server as a message transport — no additional broker required

The Nimbus SQL Server transport stores messages in database tables and delivers them via polling. If your application already uses SQL Server, this is the easiest way to add messaging — no extra broker, no new infrastructure to manage, and HA through your existing SQL Server setup.

Messages are dequeued atomically using DELETE ... OUTPUT with UPDLOCK, READPAST hints, so multiple consumers can drain a queue in parallel without duplicates or blocking.

Installation

dotnet add package Nimbus.Transports.SqlServer

Quick Start

using Nimbus;
using Nimbus.Configuration;
using Nimbus.Transports.SqlServer;

var bus = new BusBuilder()
    .Configure()
    .WithNames("OrderService", Environment.MachineName)
    .WithTransport(new SqlServerTransportConfiguration()
        .WithConnectionString("Server=localhost;Database=Nimbus;Integrated Security=true;")
        .WithAutoCreateSchema())
    .WithTypesFrom(typeProvider)
    .WithAutofacDefaults(container)
    .Build();

await bus.Start();

WithAutoCreateSchema() creates the three required tables (NimbusMessages, NimbusSubscriptions, NimbusDeadLetters) on startup if they don’t exist. It’s idempotent and safe to leave enabled in production. If you prefer to manage the schema yourself, omit it and create the tables manually using the SQL below.

Configuration

Poll Interval

The default poll interval is 1 second. Reduce it for lower latency at the cost of more database queries:

new SqlServerTransportConfiguration()
    .WithConnectionString("...")
    .WithPollInterval(TimeSpan.FromMilliseconds(250))
Poll intervalMessage latencyDB queries/consumer/min
100 ms~100 ms600
250 ms~250 ms240
1000 ms (default)~1 s60
5000 ms~5 s12

Schema

Three tables are required. WithAutoCreateSchema() creates these automatically, or run the SQL manually:

NimbusMessages

CREATE TABLE dbo.NimbusMessages (
    MessageId    UNIQUEIDENTIFIER NOT NULL PRIMARY KEY,
    Destination  NVARCHAR(255)    NOT NULL,
    Body         VARBINARY(MAX)   NOT NULL,
    VisibleAfter DATETIME2        NOT NULL,
    ExpiresAt    DATETIME2        NULL
);

CREATE INDEX IX_NimbusMessages_Dequeue
    ON dbo.NimbusMessages (Destination, VisibleAfter)
    INCLUDE (ExpiresAt);

NimbusSubscriptions

CREATE TABLE dbo.NimbusSubscriptions (
    TopicName       NVARCHAR(255) NOT NULL,
    SubscriberQueue NVARCHAR(255) NOT NULL,
    PRIMARY KEY (TopicName, SubscriberQueue)
);

NimbusDeadLetters

CREATE TABLE dbo.NimbusDeadLetters (
    MessageId           UNIQUEIDENTIFIER NOT NULL PRIMARY KEY,
    OriginalDestination NVARCHAR(255)    NULL,
    Body                VARBINARY(MAX)   NOT NULL,
    DeliveryAttempts    INT              NOT NULL,
    FailedAt            DATETIME2        NOT NULL DEFAULT SYSUTCDATETIME()
);

Limitations

  • Polling-based delivery means latency is bounded by the poll interval
  • No large message body store — all payloads stored as VARBINARY(MAX); use a claim-check pattern for large data

Compatibility

  • SQL Server 2016+
  • Azure SQL Database
  • SQL Server on Linux (Docker)
  • Microsoft.Data.SqlClient 5.x