MongoDB Persistence

Component: MongoDB Persistence (Ryan Hoffman)
NuGet Package NServiceBus.Persistence.MongoDb (8.x)
This is a community run project
Target NServiceBus Version: 5.x

Prerequisites

Ensure an instance of MongoDB is running on localhost:27017. See Install MongoDB on Windows.

MongoDB Management UI

To visualize the data in MongoDB it is useful to have install a MongoDB administration tool. The screen shots shown in this sample use Robomongo.

Code walk-through

This sample shows a simple Client + Server scenario.

  • Client sends a StartOrder message to Server
  • Server starts an OrderSaga.
  • OrderSaga requests a timeout with a CompleteOrder data.
  • When the CompleteOrder timeout fires the OrderSaga publishes a OrderCompleted event.
  • The Server then publishes a message that the client subscribes to.
  • Client handles OrderCompleted event.

MongoDB configuration

The Server endpoint is configured to use the MongoDB persistence with a connection string of mongodb://localhost:27017/SamplesMongoDBServer.

var busConfiguration = new BusConfiguration();
busConfiguration.EndpointName("Samples.MongoDB.Server");
var persistence = busConfiguration.UsePersistence<MongoDbPersistence>();
persistence.SetConnectionString("mongodb://localhost:27017/SamplesMongoDBServer");

Order Saga Data

NServiceBus.Persistence.MongoDB requires a property on the saga decorated with attribute [DocumentVersion], usually named Version.

public class OrderSagaData :
    IContainSagaData
{
    public Guid Id { get; set; }
    public string Originator { get; set; }
    public string OriginalMessageId { get; set; }

    [DocumentVersion]
    public int Version { get; set; }

    [Unique]
    public Guid OrderId { get; set; }
    public string OrderDescription { get; set; }
}

Order Saga

public class OrderSaga :
    Saga<OrderSagaData>,
    IAmStartedByMessages<StartOrder>,
    IHandleTimeouts<CompleteOrder>
{
    IBus bus;
    static ILog log = LogManager.GetLogger<OrderSaga>();

    public OrderSaga(IBus bus)
    {
        this.bus = bus;
    }

    protected override void ConfigureHowToFindSaga(SagaPropertyMapper<OrderSagaData> mapper)
    {
        mapper.ConfigureMapping<StartOrder>(message => message.OrderId)
            .ToSaga(sagaData => sagaData.OrderId);
    }

    public void Handle(StartOrder message)
    {
        Data.OrderId = message.OrderId;
        var orderDescription = $"The saga for order {message.OrderId}";
        Data.OrderDescription = orderDescription;
        log.Info($"Received StartOrder message {Data.OrderId}. Starting Saga");
        log.Info("Order will complete in 5 seconds");
        var timeoutData = new CompleteOrder
        {
            OrderDescription = orderDescription
        };
        RequestTimeout(TimeSpan.FromSeconds(5), timeoutData);
    }

    public void Timeout(CompleteOrder state)
    {
        log.Info($"Saga with OrderId {Data.OrderId} completed");
        var orderCompleted = new OrderCompleted
        {
            OrderId = Data.OrderId
        };
        bus.Publish(orderCompleted);
        MarkAsComplete();
    }
}

The Data in MongoDB

The data in MongoDB is stored in three different collections.

The Saga Data

  • IContainSagaData.Id maps to the native MongoDB document _id
  • IContainSagaData.Originator and IContainSagaData.OriginalMessageId map to simple properties pairs.
  • Custom properties on the SagaData, in this case OrderDescription and OrderId, are also mapped to simple properties.
  • _t is type serialization metadata use by the underlying MongoDB Driver.
  • DocumentVersion used by NServiceBus.Persistence.MongoDB to prevent concurrency issues.

The Timeouts

  • The subscriber is stored in a Destination with the nested properties Queue and Machine.
  • The endpoint that initiated the timeout is stored in the OwningTimeoutManager property
  • The connected saga ID is stored in a SagaId property.
  • The serialized data for the message is stored in a State property.
  • The scheduled timestamp for the timeout is stored in a Time property.
  • Any headers associated with the timeout are stored in an array of key value pairs.

The Subscriptions

Note that the message type maps to multiple subscriber endpoints.

  • The Subscription message type and version are stored as a composite key in the MongoDB document _id property.
  • The list of subscribers is stored in a array of strings containing Queue@MachineName values.

Related Articles

  • Sagas
    NServiceBus uses event-driven architecture to include fault-tolerance and scalability in long-term business processes.

Last modified