To use the transactional session feature with RavenDB persistence, add a reference to the NServiceBus.
NuGet package.
Configuration
To enable the transactional session feature:
var persistence = config.UsePersistence<RavenDBPersistence>();
persistence.EnableTransactionalSession();
Opening a session
To open a RavenDB transactional session:
using var childScope = serviceProvider.CreateScope();
var session = childScope.ServiceProvider.GetService<ITransactionalSession>();
await session.Open(new RavenDbOpenSessionOptions());
// use the session
await session.Commit();
Multi-tenancy support
The specific tenant database name is retrieved from message headers as configured in the SetMessageToDatabaseMappingConvention
-method. This header needs to be set in the options to make the necessary information available when storing operations and interacting with the outbox.
using var childScope = serviceProvider.CreateScope();
var session = childScope.ServiceProvider.GetService<ITransactionalSession>();
await session.Open(
new RavenDbOpenSessionOptions(
new Dictionary<string, string>
{
// information is added to the message headers for the `SetMessageToDatabaseMappingConvention`-method
{"tenantDatabaseName", "tenantA-databaseName"}
}));
// use the session
await session.Commit();
Transactions usage
Message and database operations made via the transactional session are committed together once the session is committed:
await session.Open(new RavenDbOpenSessionOptions());
// add messages to the transaction:
await session.Send(new MyMessage());
// access the database:
var ravenSession = session.SynchronizedStorageSession.RavenSession();
await session.Commit();
For further details about using the transaction, see the RavenDB shared session documentation.
In order to guarantee atomic consistency across message and database operations, the outbox must be enabled. Otherwise Commit
executes database modifications first and then messages are dispatched with best-effort.