Marten
Marten is an open source library that provides provides .NET developers with the ability to easily use the proven PostgreSQL database engine and its fantastic JSON support as a fully fledged document database. To use Marten and PostgreSQL as saga persistence, you need to install MassTransit.Marten
NuGet package and add some code.
MassTransit will automatically configure the CorrelationId property so that Marten will use that property as the primary key. No attribute is necessary.
public class OrderState :
SagaStateMachineInstance
{
public Guid CorrelationId { get; set; }
public string CurrentState { get; set; }
public DateTime? OrderDate { get; set; }
}
Configuration
To configure Marten and use it as a saga repository with MassTransit, use the MartenRepository
method when adding the saga.
services.AddMarten(options =>
{
const string connectionString = "host=localhost;port=5432;database=orders;username=web;password=webpw;";
options.Connection(connectionString);
});
services.AddMassTransit(x =>
{
x.AddSagaStateMachine<OrderStateMachine, OrderState>()
.MartenRepository();
});
Repository Provider
When adding sagas using any of the AddSagas
or AddSagaStateMachines
methods, the Marten saga repository provider can be used to automatically configure Marten as the saga repository.
services.AddMarten(options =>
{
const string connectionString = "host=localhost;port=5432;database=orders;username=web;password=webpw;";
options.Connection(connectionString);
});
services.AddMassTransit(x =>
{
x.SetMartenSagaRepositoryProvider();
var entryAssembly = System.Reflection.Assembly.GetEntryAssembly();
x.AddSagaStateMachines(entryAssembly);
});
To configure the saga repository for a specific saga type, use the AddSagaRepository
method and specify the appropriate saga repository.
services.AddMassTransit(x =>
{
x.SetMartenSagaRepositoryProvider();
var entryAssembly = System.Reflection.Assembly.GetEntryAssembly();
x.AddSagaStateMachines(entryAssembly);
x.AddSagaRepository<OrderState>()
.MartenRepository();
});
Optimistic Concurrency
To use Marten's built-in optimistic concurrency, which uses an eTag-like version metadata field, an additional schema configuration may be specified.
This does not require any additional fields in the saga class.
services.AddMassTransit(x =>
{
x.AddSagaStateMachine<OrderStateMachine, OrderState>()
.MartenRepository(r => r.UseOptimisticConcurrency(true));
});
Alternatively, you can add the UseOptimisticConcurrency
attribute to the saga class.
[UseOptimisticConcurrency]
public class OrderState :
SagaStateMachineInstance
{
public Guid CorrelationId { get; set; }
// ...
}
Index Creation
Marten can create indices for properties, which greatly increases query performance. If your saga is correlating events using other saga properties, index creation is recommended. For example, if an OrderNumber property was added to the OrderState class, it could be indexed by configuring it in the repository.
public class OrderState :
SagaStateMachineInstance
{
public Guid CorrelationId { get; set; }
public string CurrentState { get; set; }
public string OrderNumber { get; set; }
public DateTime? OrderDate { get; set; }
}
services.AddMarten(options =>
{
const string connectionString = "host=localhost;port=5432;database=orders;username=web;password=webpw;";
options.Connection(connectionString);
});
services.AddMassTransit(x =>
{
x.AddSagaStateMachine<OrderStateMachine, OrderState>()
.MartenRepository(r => r.Index(x => x.OrderNumber));
});
Details on how Marten creates indices is available in the Indexing documentation.