ID : dispatch.processor-coupling
Name : Processor pipeline coupling
Maturity : GA
Summary : Pipelined inbox and outbox processors lease envelopes, invoke the registered dispatcher inside a per-message DI scope, and persist terminal outcomes from dispatch exceptions.
PipelinedInboxProcessor and PipelinedOutboxProcessor are the only processor implementations in v6. Each pass leases a batch, fans work to DispatcherConcurrency workers, renews leases on a heartbeat interval, and calls DispatchAsync on the registered dispatcher. Dispatch failures throw; the processor maps exceptions to Failed or DeadLettered store state according to retry policy.
Background services register through the module manifest when EnableInboxProcessor() or EnableOutboxProcessor() runs. Startup fails if no dispatcher is registered. Each dispatched message resolves IInboxDispatcher or IOutboxDispatcher from a per-message scope so scoped handlers (for example DbContext) are isolated.
Hook failure policies differ by dispatcher type. Transport outbox dispatch defaults to CompleteDespiteHookFailure; in-process outbox and inbox processors default to DeadLetter when after-dispatch hooks fail.
Package Role LiteBus.InboxPipelinedInboxProcessor, processor hostingLiteBus.OutboxPipelinedOutboxProcessor, processor hostingLiteBus.Inbox.AbstractionsIInboxDispatcher, processor optionsLiteBus.Outbox.AbstractionsIOutboxDispatcher, IOutboxDispatcherModule.DefaultHookFailurePolicyLiteBus.Messaging.AbstractionsProcessorHookFailurePolicy, hook contracts
durable-core.inbox.processor or durable-core.outbox.processor
dispatch.registration (a dispatcher must be registered)
durable-core.*.storage (lease and state writers)
At-least-once dispatch: crash between external side effect and terminal persist can produce duplicates.
Outbox processors dispatch before terminal published state is persisted; broker ack without persist can republish on lease reclaim.
Per-message dispatch failures do not abort sibling workers in the same pass; pass-level abort applies to leasing and shutdown cancellation.
In-flight rows may remain Processing until lease expiry on graceful shutdown unless drained.
Does not implement exactly-once side effects or two-phase publish acknowledgment.
Does not choose the dispatcher implementation (registration is explicit).
Does not return handler results to the original accept/enqueue caller.
inbox. EnableInboxProcessor ( options =>
{
options.DispatcherConcurrency = 4 ;
options.LeaseHeartbeatInterval = TimeSpan. FromSeconds ( 10 );
});
Package LiteBus.Inbox.AbstractionsCalled by PipelinedInboxProcessor via per-message DI scopeContract Throw on failure; processor records retry or dead-letter
Package LiteBus.Outbox.AbstractionsCalled by PipelinedOutboxProcessor via per-message DI scopeContract Throw on failure; processor records retry or dead-letter
Member Role ProcessPendingAsync(CancellationToken)One processor pass: lease batch, dispatch workers, persist outcomes Constructor options InboxProcessorOptions / OutboxProcessorOptions
Key options affecting dispatch coupling:
Option Role DispatcherConcurrencyParallel dispatch workers per pass LeaseHeartbeatIntervalLease renewal during slow dispatch HookFailurePolicyTerminal state when after-dispatch hooks fail HonorShutdownTokenOnPersistWhether persist honors shutdown token (duplicate-dispatch trade-off)
Before/after hooks around each leased envelope (saga, custom). Hook failures interact with HookFailurePolicy and IOutboxDispatcherModule.DefaultHookFailurePolicy on transport outbox modules.
Signal Name When Inbox processor state litebus.inbox.processor.state (Running, Paused, Draining)Processor lifecycle transitions Outbox processor state litebus.outbox.processor.stateSame for outbox Pass counters litebus.inbox.processor.passes, litebus.outbox.processor.passesEach processor pass start Success counters litebus.inbox.processor.succeeded, litebus.outbox.processor.publishedTerminal success after dispatch + hooks Failure counters litebus.inbox.processor.failed, litebus.outbox.processor.failedDispatch or hook failure with retry scheduled Dead-letter counters litebus.inbox.processor.dead_lettered, litebus.outbox.processor.dead_letteredMax attempts or hook dead-letter policy Loop errors litebus.inbox.processor.loop_errors, litebus.outbox.processor.loop_errorsUnexpected pass-level exceptions Dispatch duration litebus.inbox.processor.dispatch_duration, litebus.outbox.processor.dispatch_durationHistogram around each DispatchAsync invocation Lease lost litebus.inbox.processor.lease_lost, litebus.outbox.processor.lease_lostHeartbeat renewal failure cancels in-flight dispatch Transport send send {destination} activityEmitted by the concrete transport publisher during processor-driven dispatch
No separate OpenTelemetry meter on IInboxDispatcher implementations; all dispatch-axis processor telemetry flows through inbox/outbox processor meters.
LB1014 : Processor enabled without dispatcher in the same builder scope.
Test method Project PipelinedProcessor_WithConcurrencyOne_ShouldProcessAllCommandsLiteBus.Inbox.UnitTestsPipelinedProcessor_WithParallelWorkers_ShouldDispatchConcurrentlyLiteBus.Inbox.UnitTestsPipelinedProcessor_WithHeartbeat_ShouldCompleteSlowHandlerWithoutReclaimLiteBus.Inbox.UnitTestsPipelinedProcessor_when_after_dispatch_hook_fails_should_not_redispatch_handlerLiteBus.Inbox.UnitTestsPipelinedProcessor_when_after_dispatch_hook_fails_should_persist_dead_letter_without_completedLiteBus.Inbox.UnitTestsPipelinedProcessor_when_hook_failure_policy_is_complete_despite_hook_failure_should_mark_completedLiteBus.Inbox.UnitTestsPipelinedProcessor_when_lease_renewal_fails_should_cancel_dispatchLiteBus.Inbox.UnitTestsProcessPendingAsync_when_after_dispatch_hook_fails_should_dead_letter_from_processingLiteBus.Storage.IntegrationTests (PostgreSql/)ProcessPendingAsync_parallel_workers_should_produce_single_terminal_state_per_messageLiteBus.Storage.IntegrationTests (PostgreSql/)PipelinedProcessor_when_after_dispatch_hook_fails_should_not_redispatchLiteBus.Outbox.UnitTestsPipelinedProcessor_when_after_dispatch_hook_fails_should_persist_dead_letter_without_publishedLiteBus.Outbox.UnitTestsPipelinedProcessor_when_hook_failure_policy_is_complete_despite_hook_failure_should_mark_publishedLiteBus.Outbox.UnitTestsProcessPendingAsync_WhenPersistSkippedAfterPublish_ShouldRepublishOnRetryLiteBus.Durable.IntegrationTests (Dispatch/Outbox/InMemory/)ProcessPendingAsync_WithConcurrentMessages_ShouldIsolateAndDisposeScopedDbContextsLiteBus.Storage.IntegrationTests (EntityFrameworkCore/Inbox/)ProcessPendingAsync_WhenShutdownBeginsAfterAmqpPublish_ShouldApplyTerminalPersistPolicyLiteBus.Durable.IntegrationTests (Dispatch/Outbox/Amqp/)StopAsync_WhenInboxDispatchIsActive_ShouldWaitForCompletionAndPersistTerminalStateLiteBus.Runtime.UnitTests (Runtime/Hosting/)
Exactly-once side effects or two-phase publish acknowledgment
Automatic dispatcher selection (registration is explicit)
Returning handler or mediator results to the original accept/enqueue caller