LiteBus
Migration

Migration Guide v6

Greenfield v6 replaces v5 writer APIs and module composition. Current PostgreSQL schemas are inbox/outbox version 3 and saga version 2. This guide covers both the original v6 break from v5 and the v6.0 rename tables for application code that still references legacy identifiers from v5 or early v6 package versions. Shipping libraries in src/ use v6 names exclusively.

Related: API design (suffix taxonomy, CLR kind rules, inbox/outbox Message model), v6 feature index, Dependency graph.

Historical upgrades: Migration Guide v5, Migration Guide v4.


Greenfield v6 (from v5)

Adopt v6 as a fresh integration:

Areav5v6
Target framework.NET 8/9net10.0 only
Command schedulingICommandScheduler.ScheduleAsyncIInbox.AcceptAsync with InboxAcceptItem
Event publication (durable)IOutboxWriter.AddAsyncIOutbox.EnqueueAsync with OutboxEnqueueItem
Module registrationFlat storage/dispatch registrarsPackage extensions on ILiteBusBuilder, with nested inbox/outbox adapters
PostgreSQL schemaUpgrade scripts from v5Current-version greenfield DDL; ordered migrations within v6; no automatic v5 upgrade
ProcessorsSequential legacy loopsPipelined processors only
RegistryProcess-wide MessageRegistryOne registry per IModuleConfiguration
RemovedIEventPublisher, IIdempotentCommand, v5 scheduler aliasesSee Changelog v6.0.0

Writer items use *Metadata for idempotency, visibility, trace, and tenant concerns. InboxOptions, OutboxOptions, IInboxScheduler, and IOutboxScheduler are removed.

Append stores now return InboxAppendResult or OutboxAppendResult from AddAsync and ordered lists of those results from AddBatchAsync. Custom providers must return Accepted / Enqueued only for a new row and AlreadyAccepted / AlreadyEnqueued when either the message ID or tenant-scoped idempotency key resolves an existing row. Writer receipts expose the same axis-specific outcome. The homogeneous IOutbox.EnqueueBatchAsync<TEvent> overload is removed; convert typed items to OutboxEnqueueItem and call the canonical heterogeneous batch overload.

Existing PostgreSQL Databases

New-install scripts contain the current table shape. Existing v6 tables must apply the shipped migrations in order before application startup:

  1. Inbox and outbox v2: convert payload from jsonb to opaque text.
  2. Inbox and outbox v3: add lease_generation bigint NOT NULL DEFAULT 0.
  3. Saga v2: add nullable last_applied_message_id uuid.

After applying the files exposed by each PostgreSql*Schema.SqlFiles catalog, call EnsureAsync to validate column names and types and to record the current version. EnsureAsync creates a missing current-version table but does not execute migrations against an existing table.

Current create scripts also use a tenant-scoped idempotency unique index on (tenant_id, idempotency_key) where idempotency_key IS NOT NULL. Deployments created before this index shape must run the manual index migration once per table:

  1. Normalize unscoped rows: UPDATE <table> SET tenant_id = '' WHERE tenant_id IS NULL.
  2. Drop the legacy single-column idempotency unique index.
  3. Create the composite unique index on (tenant_id, idempotency_key) with the same partial filter.

Embedded SQL: Sql/inbox/v1/migrate_tenant_idempotency_index.sql and Sql/outbox/v1/migrate_tenant_idempotency_index.sql. Running ensure_indexes on a new table applies the composite index directly. Coordinate inbox, outbox, and saga changes when the components share one database.

Entity Framework Core model configuration maps the same composite index and lease_generation column. Regenerate or alter EF migrations after upgrading store packages so application-owned migrations match the current shape.


v6.0 Rename Reference

The v6.0 rename pass is complete in shipping packages: src/ contains no legacy identifiers from the tables below. Use the tables when upgrading your solution from v5, from early v6 package versions, or from copied samples that still use legacy names.

Mediation and Handlers

Legacy (remove from apps)v6 (keep in libraries)Notes
MessageMediationRequest with embedded CancellationTokenMessageMediationRequest<TMessage, TResult>Pass CancellationToken only on IMessageMediator.Mediate(..., cancellationToken)
MultipleCommandHandlerFoundExceptionMultipleHandlerFoundExceptionConsolidated type in LiteBus.Messaging.Abstractions
MultipleMessageHandlerFoundExceptionMultipleHandlerFoundExceptionSame consolidation
MultipleQueryHandlerFoundExceptionMultipleHandlerFoundExceptionSame consolidation
HandleErrorAsync(message, result, exception, cancellationToken)HandleErrorAsync(MessageErrorContext<TMessage, TResult>, cancellationToken)Read failure data from the typed context; set Outcome and optional HandledResult there to recover
IMessageErrorHandler.HandleError(MessageErrorContext)IMessageErrorHandler.HandleErrorAsync(MessageErrorContext, CancellationToken)The runtime base contract is asynchronous and receives cancellation explicitly
IMessageMediator.MediateAsync<TMessage, TResult>(...)IMessageMediator.Mediate<TMessage, TResult>(...)Async strategies use Task or Task<TResult> as TResult; await the returned value directly without creating Task<Task>

Error-handler contexts default to MessageErrorOutcome.Unhandled, so observation alone does not suppress an exception. Remove explicit implementations of the old synchronous base method and any LegacyErrorHandlerSupport calls. Set context.Outcome = MessageErrorOutcome.Handled only when the handler has recovered; result-bearing handlers also set context.HandledResult.

In-Process Dispatch (Module Builders)

Legacyv6
UseInProcessDispatcher()UseInProcessDispatch()

Both inbox and outbox in-process dispatch packages register through UseInProcessDispatch() on their respective module builders.

Entity Framework Core Storage

Legacyv6
UseEfCoreStorage(...)UseEntityFrameworkCoreStorage(...)
EfCoreInboxStoreOptions / EfCoreOutboxStoreOptionsEntityFrameworkCoreInboxStoreOptions / EntityFrameworkCoreOutboxStoreOptions

Regenerate application-owned inbox and outbox migrations after updating the EF storage packages. The current model adds IX_LiteBus_Inbox_CreatedAt and IX_LiteBus_Outbox_CreatedAt; MySQL lease queries require these names for ordered skip-locked scans. Existing SQLite tables must convert every durable timestamp column from the provider's DateTimeOffset representation to UTC ticks stored as INTEGER. Rebuilding a SQLite table through an EF migration is the safest conversion path. PostgreSQL and SQL Server timestamp column types do not change.

MySQL and SQLite model mappings do not apply a schema qualifier. MySQL lease SQL uses the current connection database, and SQLite uses the current database file. Keep SchemaName aligned for providers that support schemas, including PostgreSQL and SQL Server.

AWS SQS Packages (NuGet IDs)

Legacy package IDv6 package ID
LiteBus.Transport.AwsSqsSqsLiteBus.Transport.AwsSqs
LiteBus.Inbox.Dispatch.AwsSqsSqsLiteBus.Inbox.Dispatch.AwsSqs
LiteBus.Outbox.Dispatch.AwsSqsSqsLiteBus.Outbox.Dispatch.AwsSqs
LiteBus.Inbox.Ingress.AwsSqsSqsLiteBus.Inbox.Ingress.AwsSqs

Extension method names (UseAwsSqsDispatch, UseAwsSqsIngress) are unchanged.

ASP.NET Management Bindings

Legacyv6
*QueryParameters*QueryBinding
*PurgeParameters*PurgeBinding

Durable Writer Items (Inbox/Outbox Symmetry)

Legacyv6Notes
OutboxEnqueueItem.EventMessageDurable vocabulary is message-centric
Outbox untyped EventTypeMessageTypeAligns with InboxReceipt.MessageType
InboxAcceptItems / OutboxEnqueueItems(removed)Use static factories on InboxAcceptItem / OutboxEnqueueItem

OutboxEnqueueItem<TEvent> keeps the TEvent type parameter at the CQRS layer.

Event Mediation Settings

Legacyv6
Nested settings bags on EventMediationSettingsEventRoutingSettings, EventExecutionSettings, EventHandlerFilter

Saga Module Extensions

Legacyv6
InboxModuleBuilderExtensions (saga package)InboxModuleBuilderSagaExtensions
InboxModuleBuilderExtensions (PostgreSQL saga)SagaModuleBuilderPostgreSqlExtensions

Composition and Package Boundaries

Early v6 surfaceCurrent v6 surfaceMigration
AddLiteBus(Action<IModuleRegistry>)AddLiteBus(Action<ILiteBusBuilder>)Use package-owned extensions for normal composition and builder.Modules.Register(...) for custom modules.
builder.Modules.AddMessageModule(...)builder.AddMessaging(...)Use package-owned root extensions for normal application composition.
builder.Modules.AddCommandModule/AddQueryModule/AddEventModulebuilder.AddCommands/AddQueries/AddEventsKeep builder.Modules only for advanced module registry access.
builder.Modules.AddInboxModule/AddOutboxModulebuilder.AddInbox/AddOutboxStorage, dispatch, and ingress remain nested on their feature builders.
LiteBus.Orchestration.AbstractionsLiteBus.DurableMessaging.AbstractionsReplace the project or NuGet reference. Shared durable contracts now live in the renamed package.
IMessageTransportITransportPublisherConsumption remains on IMessageConsumer.
Module-level ITransportCircuitBreakerITransportCircuitBreakerRegistryResolve publisher state with GetPublisherCircuit(destination). Ingress does not consume publisher breaker state.
ThrowIfOpen() plus parameterless breaker outcome methodsAcquirePermit() plus RecordSuccess(permit) or RecordFailure(permit)Keep the permit for the operation lifetime so stale completions cannot reset a newer breaker generation.
One TransportConsumerOptions.PrefetchCount used for every brokerMaxInFlightMessages, native PrefetchCount, ReceiveBatchSize, and MaxConcurrentCallsUse MaxInFlightMessages for the common LiteBus callback cap. Configure only the native fields supported by the selected adapter.
TransportConsumerOptions.MaxConcurrentMessagesMaxConcurrentCallsThe name now matches Azure Service Bus processor callback semantics.
AwsSqsInboxIngressOptions.PrefetchCountReceiveBatchSizeUse a value from 1 through 10. Invalid values fail during module composition.
KafkaInboxIngressOptions.PrefetchCount, InMemoryInboxIngressOptions.PrefetchCountRemovedNeither adapter honored the setting. Use Safety.MaxInFlightMessages for LiteBus callback admission.
Unbounded in-memory destination channelsInMemoryTransportOptions.DestinationCapacity, default 1024Pass the options to AddInMemoryTransport(...). Publication now waits when queued and in-flight deliveries reach the per-destination limit.
AMQP-only broker readinessAMQP, Kafka, AWS SQS, and Azure Service Bus root transport probesSet AwsSqsTransportOptions.ConnectivityCheckQueueUrl or AzureServiceBusTransportOptions.ConnectivityCheckTarget. Kafka uses ConnectivityCheckTimeout. Missing SQS or Azure targets report degraded.
Fixed host diagnostic runner settingsLiteBusHealthCheckOptions.DiagnosticChecks and LiteBusManagementOptions.DiagnosticChecksConfigure per-probe Timeout and MaxParallelism; defaults are 5 seconds and 4 probes. The health-check registration is tagged litebus and ready.
Flat ingress MaxMessageBytes, identity, trust, authorization, or batch propertiesNested Safety on every broker ingress options recordMove common settings into TransportInboxIngressSafetyOptions. AMQP trust and batch properties moved under AmqpInboxIngressOptions.Safety too.
IRegistrableCommandConstruct, IRegistrableQueryConstruct, IRegistrableEventConstructRemovedRegister actual semantic messages and handlers; no marker replacement is needed.
Broker options passed to Use*Dispatch or ingress ConnectionAddAmqpTransport, AddKafkaTransport, AddAwsSqsTransport, AddAzureServiceBusTransport, or AddInMemoryTransportRegister one shared transport at the root, then configure dispatch and ingress routing only.
Implicit root-provider dispatchContainer IMessageDispatchScopeFactoryUse the Microsoft DI or Autofac adapter. Manual hosts must register RootMessageDispatchScopeFactory explicitly.
EF store resolving a scoped DbContextIDbContextFactory<TContext>Register the context with AddDbContextFactory<TContext> before selecting it with UseDbContext<TContext>().
Saga implicit in-memory fallback or flat PostgreSQL registrationStorage selected inside EnableSaga(...)Call exactly one of UseInMemoryStorage() or UsePostgreSqlStorage(...) on SagaModuleBuilder.
OutboxEnvelope.AsPublished()OutboxEnvelope.AsPublished(publishedAt)Pass the processor clock timestamp explicitly.

Testing Support Packages

Legacyv6Notes
FakeCommandMediator, FakeQueryMediator, other mediator Fake* typesMatching Test* names in LiteBus.Testing.MediationReference only semantic mediator abstractions
Inbox/outbox Fake* stores and processor helpersMatching Test* names in LiteBus.Testing.DurableMessagingReference durable support only when the test needs it
Transport Fake* typesTestMessageTransport in LiteBus.Testing.TransportDoes not pull broker SDKs or durable packages
Host lifecycle helpersLiteBus.Testing.HostingKeeps Generic Host dependencies out of mediator and transport tests
ManualTimeProvider, LiteBusTestBaseLiteBus.TestingThe base package is framework-neutral

Not in scope: sample message types in test projects (for example FakeCommand, FakeParentCommand under tests/**/FakeCommand/ folders) are ordinary command fixtures used to exercise the mediation pipeline. They are unrelated to LiteBus.Testing and do not need renaming.


Intentionally Unchanged

  • SendAsync / PublishAsync / QueryAsync on semantic mediators
  • IOutbox.EnqueueAsync method name
  • OutboxEnqueueItem<TEvent> type name and TEvent type parameter
  • Granular package split (inbox vs outbox, per broker, per store)
  • Use* registration pattern on module builders

Application Migration Checklist

When upgrading a consumer solution, search application code, samples, and copied test helpers (not shipping library sources) for legacy identifiers from the tables above. In particular, replace:

  • UseInProcessDispatcher (use UseInProcessDispatch)
  • UseEfCoreStorage (use UseEntityFrameworkCoreStorage)
  • FakeCommandMediator, FakeQueryMediator, and other legacy testing Fake* doubles (use the matching Test* type and concern package; do not rename unrelated test message fixtures such as FakeCommand)
  • *QueryParameters / *PurgeParameters on public ASP.NET types (use *Binding)
  • item.Event / untyped outbox EventType (use Message / MessageType)
  • MultipleCommandHandlerFoundException, MultipleMessageHandlerFoundException, MultipleQueryHandlerFoundException
  • NuGet or project references ending in AwsSqsSqs or *.Aws transport/dispatch/ingress IDs (use *.AwsSqs package IDs)

Current v6 names such as MessageMediationRequest<TMessage, TResult>, UseInProcessDispatch, UseEntityFrameworkCoreStorage, LeaseRenewalRequest, SagaSaveItem<TState>, MessageErrorContext, and InboxAcceptMetadata.Immediate are expected in shipping libraries.

Run dotnet build on your solution after applying renames.


Next

On this page