Reliable Messaging Semantics
Production tier: GA
Deep reference for delivery guarantees, idempotency, and broker behavior in LiteBus v6. For registration and package layout, start with Reliable messaging. For atomic domain + inbox/outbox writes, see Transactional messaging writes.
At-Least-Once
LiteBus durable paths persist before execution (inbox) or before broker publish completes terminal state (outbox). A worker may therefore run the same logical message more than once after crash, lease expiry, or broker redelivery.
Applications must make handlers idempotent or deduplicate using:
InboxAcceptMetadata.Idempotency/OutboxEnqueueMetadata.Idempotency(Idempotency.Keyed)- Natural keys in domain stores
- Broker message IDs where consumers support dedup
Inbox Accept vs Execute
| Step | API | Committed when |
|---|---|---|
| Accept | IInbox.AcceptAsync | Row visible in store (Pending) |
| Execute | PipelinedInboxProcessor + dispatcher | Terminal status after successful dispatch |
Accept is durable once the store transaction commits. Execution is at-least-once under lease.
Outbox Enqueue vs Publish
| Step | API | Committed when |
|---|---|---|
| Enqueue | IOutbox.EnqueueAsync | Row in store (often same UoW as domain change) |
| Publish | Processor + IOutboxDispatcher | Terminal Published/Failed/DeadLettered |
Transactional outbox: enqueue in the same database transaction as domain entities. EF uses the save-changes interceptor; PostgreSQL uses ITransactionalOutbox with ambient provider or manual bind. See Transactional messaging writes and Domain events and unit of work.
Lease Recovery
Processors lease batches with lease_owner and lease_expires_at. Heartbeat renews leases during long handlers. When lease expires:
- Another worker may lease the same row
- Terminal persist uses conditional update (
lease_ownermatch) to avoid overwriting a newer attempt
PostgreSQL and EF Core stores use atomic conditional persist.
Drain Before Stop
Hosted services run IBackgroundService processor loops. On shutdown:
- Drain control stops new leases
- In-flight dispatches complete (subject to cancellation token policy)
HonorShutdownTokenOnPersiston processor options controls whether cancel aborts terminal persist (default: complete persist)
See Hosted services and Production runbook.
Broker Ingress Ack Policy
| Broker | Commit/ack timing | Failure before accept |
|---|---|---|
| Kafka | Offset commit on ack | Seek back; no commit |
| AMQP | BasicAck after accept | Nack requeue or reject |
| SQS | Delete on ack | Visibility timeout extension |
| Azure | Complete/abandon per SDK | Abandon for retry |
Ingress logs ingress.ack_failed_after_accept when ack fails after successful accept; broker may redeliver (at-least-once).
Schema v1 Greenfield
PostgreSQL inbox and outbox tables use schema version 3; saga uses version 2. Ordered migrations cover older v6 tables. No automatic upgrade exists for LiteBus v5 tables. See Migration Guide v6.
Comparison Table
| Concern | In-process mediator | Durable inbox/outbox |
|---|---|---|
| Crash safety | None | Store + processor |
| Ordering | Handler pipeline order | FIFO-like by created_at; no strict order for ties, retries, or multiple workers |
| Duplicates | None | Possible; idempotency required |
| Cross-service | Single process | Storage + optional broker |
Tests
| Scenario | Location |
|---|---|
| Contract store semantics | LiteBus.Storage.Testing |
| Concurrent lease / persist | PostgreSQL + EF integration tests |
| Ingress requeue | Broker integration tests under LiteBus.Composition.UnitTests |