IPersistenceConfiguration
Overview
Section titled “Overview”IPersistenceConfiguration exposes the provider-agnostic persistence settings used by process managers, aggregators, and the timeout store. It is reached via builder.ConfigurePersistence(p => ...) and is typically populated as a side-effect of the provider extension method you call — UseInMemoryPersistence() for tests and local development, UseMongoDbPersistence(...) for production. Both providers ship in the box.
See Process Manager for the higher-level picture of what persistence stores are storing.
Reference
Section titled “Reference”ConnectionString
Section titled “ConnectionString”string ConnectionString { get; set; }Gets or sets the provider-specific connection string.
Default: "" (empty string).
Remarks. Only meaningful for providers that connect to an external store (MongoDB). The in-memory provider ignores it.
DatabaseName
Section titled “DatabaseName”string DatabaseName { get; set; }Gets or sets the database or logical store name.
Default: "RMessageBusPersistentStore".
Remarks. MongoDB uses this as the database name. The in-memory provider ignores it.
AggregatorCollectionName
Section titled “AggregatorCollectionName”string AggregatorCollectionName { get; set; }Gets or sets the collection or container name used for aggregator state.
Default: "Aggregator".
Remarks. MongoDB uses this as the collection name for aggregator snapshots. The in-memory provider ignores it.
ICacheProvider and IKeyValueStore
Section titled “ICacheProvider and IKeyValueStore”UseInMemoryPersistence() also registers two secondary interfaces for application code that wants an in-process cache: ICacheProvider (full-featured, with expiry, sliding TTL, and priority) and IKeyValueStore (simpler, offset-expiry add/get/remove). Both resolve to the same underlying CacheProvider singleton wired to InMemoryPersistenceState.Provider.
TryGet<TKey,TValue>
Section titled “TryGet<TKey,TValue>”Both interfaces expose TryGet<TKey,TValue>(key, out value) for cache reads — the bool return distinguishes “key present” from “key absent”, which a Get overload returning default! could not.
if (cache.TryGet<string, MyType>(key, out var value)){ // key was present; value may still be null for reference-type TValue}else{ // key was absent}For value-type TValue (for example int), the out-parameter receives default(T) on miss (for example 0); only the bool return distinguishes presence from absence.
Development: in-memory persistence
Section titled “Development: in-memory persistence”services.AddServiceConnect(builder =>{ builder.UseRabbitMQ(transport => { transport.Host = "localhost"; transport.Username = "guest"; transport.Password = "guest"; });
builder.ConfigureQueues(queues => queues.QueueName = "order-service");
builder.UseInMemoryPersistence();
builder.ConfigureBus(bus => bus.EnableProcessManagerTimeouts = true);});UseInMemoryPersistence() wires up IProcessManagerFinder, ITimeoutStore, and IAggregatorPersistor against a single in-process state object. Nothing survives an app restart — ideal for tests and developer machines, never for production.
Production: MongoDB with a named database
Section titled “Production: MongoDB with a named database”services.AddServiceConnect(builder =>{ builder.UseRabbitMQ(transport => { transport.Host = "rabbit.internal.example"; transport.Username = "order-service"; transport.Password = Environment.GetEnvironmentVariable("ORDER_RABBIT_PASSWORD"); });
builder.ConfigureQueues(queues => { queues.QueueName = "order-service"; queues.ErrorQueueName = "order-service.dlq"; });
builder.UseMongoDbPersistence(options => { options.ConnectionString = Environment.GetEnvironmentVariable("ORDER_MONGO_URI"); options.DatabaseName = "OrderService"; });
builder.ConfigureBus(bus => { bus.EnableProcessManagerTimeouts = true; bus.ProcessManagerTimeoutPollInterval = TimeSpan.FromSeconds(5); });});UseMongoDbPersistence(...) registers MongoDbProcessManagerFinder, MongoDbTimeoutStore, and MongoDbAggregatorPersistor against a single shared IMongoClient. The OrderService database holds the ShippingSaga state documents alongside the timeout collection; the poll interval controls how quickly scheduled TimeoutMessage deliveries fire.
Provider options
Section titled “Provider options”InMemoryPersistenceOptions
Section titled “InMemoryPersistenceOptions”| Property | Type | Default | Description |
|---|---|---|---|
LockLeaseDuration | TimeSpan | TimeSpan.FromMinutes(5) | Lease duration applied when claiming a timeout for dispatch. Mirrors MongoDbPersistenceOptions.TimeoutLockLeaseDuration. Must be positive. |
Configure via the UseInMemoryPersistence extension’s optional configure delegate:
services.AddServiceConnect(builder =>{ builder.UseInMemoryPersistence(o => o.LockLeaseDuration = TimeSpan.FromSeconds(30));});Or register an instance directly before calling UseInMemoryPersistence (the extension’s TryAddSingleton call will skip registration if the instance is already present):
services.AddSingleton(new InMemoryPersistenceOptions { LockLeaseDuration = TimeSpan.FromSeconds(30) });services.AddServiceConnect(builder =>{ builder.UseInMemoryPersistence();});MongoDbPersistenceOptions
Section titled “MongoDbPersistenceOptions”| Property | Type | Default | Description |
|---|---|---|---|
ConnectionString | string | "" | MongoDB connection URI. Required for production deployments. |
DatabaseName | string | "" | Database name for process manager, aggregator, and timeout collections. |
TimeoutLockLeaseDuration | TimeSpan | TimeSpan.FromMinutes(5) | Lease duration applied when claiming a timeout row for dispatch. See Timeout lease semantics. |
TimeoutBatchSize | int | 100 | Maximum number of due timeout rows returned by a single GetTimeoutsBatchAsync call. |
Configure via the UseMongoDbPersistence extension’s options delegate:
services.AddServiceConnect(builder =>{ builder.UseMongoDbPersistence(options => { options.ConnectionString = Environment.GetEnvironmentVariable("MONGO_URI"); options.DatabaseName = "order-service"; options.TimeoutLockLeaseDuration = TimeSpan.FromMinutes(2); });});MongoDB provider contract
Section titled “MongoDB provider contract”The MongoDB provider enforces several requirements at startup. Violating them throws InvalidOperationException before any consumer host begins polling, so failures are loud and immediate rather than silent data corruption.
WriteConcern requirement
Section titled “WriteConcern requirement”MongoDbProcessManagerFinder, MongoDbTimeoutStore, and MongoDbAggregatorPersistor each require the IMongoClient to be configured with an acknowledged write concern (w:1 or higher). If the client’s WriteConcern is WriteConcern.Unacknowledged (w:0), construction throws InvalidOperationException — fail-fast at startup before any consumer host begins polling.
// Correct — acknowledged writes (default for most connection strings)var client = new MongoClient("mongodb://localhost:27017");
// Incorrect — will throw at startupvar settings = MongoClientSettings.FromConnectionString("mongodb://localhost:27017");settings.WriteConcern = WriteConcern.Unacknowledged;var client = new MongoClient(settings);Unacknowledged writes disable the optimistic concurrency version checks that guard against lost saga updates, and silently no-op-succeed lock-aware delete/release operations in MongoDbTimeoutStore and MongoDbAggregatorPersistor — converting a stale-lease no-op into an apparent successful delete and allowing duplicate timeout dispatch or aggregate dispatch. Rejecting w:0 at startup prevents silent data corruption.
Guid representation requirement
Section titled “Guid representation requirement”The MongoDB provider registers GuidRepresentation.Standard (RFC 4122 byte order) for all Guid serialization. If another component registers a different Guid serializer before UseMongoDbPersistence is called, startup throws InvalidOperationException.
To avoid the conflict: either remove your custom Guid serializer registration, or ensure it also uses GuidRepresentation.Standard before ServiceConnect registers. Two registrations of Standard are accepted; two registrations with different representations are not.
Startup-time index pre-creation
Section titled “Startup-time index pre-creation”A hosted service (IHostedService) runs during IHost.StartAsync and pre-creates the unique CorrelationId index for each registered saga data type before any consumer host begins polling. This closes the cross-process startup race that could admit duplicate saga rows when multiple instances start simultaneously.
The hosted service uses IProcessManagerTypeRegistry to enumerate all saga data types registered via AddProcessManager<TSaga>. No additional configuration is required; UseMongoDbPersistence registers both the hosted service and the registry automatically.
See also
Section titled “See also”- Process Manager — concept
ITimeoutStore— timeout dispatch referenceIAggregatorPersistor— related referenceIProcessManagerFinder— related reference