Getting Started
Architecture
NServiceBus
Transports
Persistence
ServiceInsight
ServicePulse
ServiceControl
Monitoring
Samples

MongoDB Persistence

NuGet Package: NServiceBus.Storage.MongoDB (4.x)
Target Version: NServiceBus 9.x

Prerequisites

Ensure an instance of MongoDB is executing on localhost:27017.

The easiest way to do this is to run MongoDB in Docker by running the following commands

docker run -d -p 27017:27017 --name TestMongoDB mongo:latest --replSet tr0
docker exec -it TestMongoDB mongosh --eval 'rs.initiate()'

Alternatively, it is possible to install MongoDB but the instance must be part of a replica set to enable transactions. If this is not possible, the endpoint configuration must be altered to disable transactions (not recommended for production):

endpointConfiguration.UsePersistence<MongoPersistence>().UseTransactions(false)

Data visualization

To visualize data in MongoDB, it is useful to install a MongoDB visualization tool. The screen shots in this sample are from Robomongo.

Code walk-through

This sample shows a simple client/server scenario:

  • Client sends a StartOrder message to Server
  • Server starts an OrderSaga instance
  • OrderSaga requests a timeout with CompleteOrder data
  • CompleteOrder timeout occurs and OrderSaga publishes an OrderCompleted event
  • OrderCompleted is delivered to Client, because Client is subscribed to that event
  • Client handles OrderCompleted

MongoDB configuration

The Server endpoint is configured to use MongoDB persistence.

var endpointConfiguration = new EndpointConfiguration("Samples.MongoDB.Server");
var persistence = endpointConfiguration.UsePersistence<MongoPersistence>();
persistence.DatabaseName("Samples_MongoDB_Server");
  • If a MongoDB URL is not specified, the persistence uses the default of mongodb://localhost:27017.
  • If a database name is not specified, the persistence uses the endpoint name as the database name. In this sample the database name is Samples_MongoDB_Server.

Order saga

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

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

    public Task Handle(StartOrder message, IMessageHandlerContext context)
    {
        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
        };

        return RequestTimeout(context, TimeSpan.FromSeconds(5), timeoutData);
    }

    public Task Timeout(CompleteOrder state, IMessageHandlerContext context)
    {
        log.Info($"Saga with OrderId {Data.OrderId} completed");

        var orderCompleted = new OrderCompleted
        {
            OrderId = Data.OrderId
        };

        MarkAsComplete();

        return context.Publish(orderCompleted);
    }
}

Saga data

The saga data is stored in the ordersagadata collection.

public class OrderSagaData : ContainSagaData
{
    public Guid OrderId { get; set; }

    public string OrderDescription { get; set; }
}

  • _id stores IContainSagaData.Id
  • _t is type serialization metadata used by the MongoDB .NET/C# Driver
  • Originator stores IContainSagaData.Originator
  • OriginalMessageId stores IContainSagaData.OriginalMessageId
  • OrderID stores OrderSagaData.OrderID
  • OrderDescription stores OrderSagaData.OrderDescription
  • _version is added and managed by the persistence to prevent concurrency issues

Related Articles

  • Sagas
    Maintain statefulness in distributed systems with the saga pattern and NServiceBus' event-driven architecture with built-in fault-tolerance and scalability.