Skip to main content
Table of Contents

Class OutboxServiceCollectionExtensions

Namespace
Microsoft.Extensions.DependencyInjection
Assembly
Stratara.Outbox.RabbitMQ.dll

Service-collection extensions for the Stratara outbox + projection-replay stack.

public static class OutboxServiceCollectionExtensions
Inheritance
OutboxServiceCollectionExtensions
Inherited Members

Methods

AddOutboxDispatcher(IServiceCollection)

public static IServiceCollection AddOutboxDispatcher(this IServiceCollection services)

Parameters

services IServiceCollection

Returns

IServiceCollection

Examples

builder.AddMessaging();
builder.Services.AddOutboxDispatcher();

Remarks

The transitive IProjectionReplayState registration is intentional: the outbox dispatchers consult it before each publish to skip the fast-path while a projection replay is in progress. The underlying registration uses TryAddSingleton, so it is safe to call this method together with AddProjectionReplayState(IServiceCollection) or AddEventProjectionWorkerServices() — duplicates collapse.

AddOutboxWorker(IServiceCollection, IConfiguration)

Registers the Stratara.Outbox.RabbitMQ.Outbox.OutboxWorker hosted service and binds OutboxOptions from configuration.

public static IServiceCollection AddOutboxWorker(this IServiceCollection services, IConfiguration configuration)

Parameters

services IServiceCollection
configuration IConfiguration

Returns

IServiceCollection

Examples

Binds OutboxOptions from the Outbox section. A cycle takes one batch of each kind, so BatchSize and PollingIntervalSeconds together set the drain rate:

// appsettings.json: { "Outbox": { "BatchSize": 10000, "PollingIntervalSeconds": 30 } }
services.AddOutboxWorker(configuration);

Remarks

Each polling cycle is guarded by IOutboxLock. The default registration is Stratara.Outbox.RabbitMQ.Outbox.NullOutboxLock, a no-op that always grants the lock — safe only for single-instance deployments. For multi-replica setups call AddRedisOutboxLock(IServiceCollection) afterwards, which overrides the no-op with a Redis-leased lock that lets only one replica drain at a time.

AddProjectionReplayState(IServiceCollection)

Registers the singleton IProjectionReplayState: Redis-backed where an StackExchange.Redis.IConnectionMultiplexer is registered, held in process otherwise. Idempotent (TryAddSingleton).

public static IServiceCollection AddProjectionReplayState(this IServiceCollection services)

Parameters

services IServiceCollection

Returns

IServiceCollection

Examples

One host needs no Redis; a deployment whose replay must reach several hosts registers the shared connection, in either order:

// appsettings.json: { "ProjectionReplay": { "LeaseSeconds": 600 } }
services.AddProjectionReplayState();
builder.AddCaching();                       // optional: makes the replay state span hosts

Remarks

The choice is made when the state is first resolved, not when this method runs, so the order of AddCaching() and the composites does not matter. With a Redis connection the replay marking, its progress and the replay-request channel are shared by every host on that connection, and a replay requested in one suppresses publication in all of them. Whether a replay is active is answered from the host's memory either way — no dispatch, publication or catch-up waits on Redis for it — and a marking that changed in another host is seen within RefreshSeconds at the latest, usually at once. Without a Redis connection the state lives in this process only — a replay requested here suppresses publication here only — and the host records that once at start-up as a warning (event 104_012). A host that registers its own IProjectionReplayState keeps it.

Also registers ProjectionReplayOptions, read from the ProjectionReplay section of the IConfiguration the container holds, so the replay marking is leased even when the consumer configures nothing. A service collection that holds no configuration gets the defaults. A value configured in code with services.Configure<ProjectionReplayOptions>(...) after this call takes precedence over the section; one configured before it is overwritten for every key the section carries. The section is applied once, at the position of the first call, so calling this method again — directly, through AddOutboxDispatcher(IServiceCollection) or through a composite — does not re-apply it.

A LeaseSeconds of zero or less is refused when the host starts, with an OptionsValidationException naming ProjectionReplay:LeaseSeconds; so is a RefreshSeconds of zero or less, or at or above the lease, naming ProjectionReplay:RefreshSeconds.

AddRedisOutboxLock(IServiceCollection)

Replaces the default Stratara.Outbox.RabbitMQ.Outbox.NullOutboxLock with the Redis-backed Stratara.Outbox.RabbitMQ.Outbox.RedisOutboxLock, enabling safe multi-instance outbox-worker deployments.

public static IServiceCollection AddRedisOutboxLock(this IServiceCollection services)

Parameters

services IServiceCollection

Returns

IServiceCollection

Examples

Required before running more than one outbox-worker replica; the default lock is a no-op that assumes a single instance. Needs an IConnectionMultiplexer, which AddCaching() registers:

builder.AddCaching();
builder.Services.AddRedisOutboxLock();

Remarks

Requires StackExchange.Redis.IConnectionMultiplexer to be registered (for example via AddCaching() from Stratara.Infrastructure). The lock is leased with LockLeaseSeconds; tune the lease to comfortably exceed the worst-case drain duration.