feat(outbox): single-commit connection sharing for consumer writes - #39
Merged
asawicki merged 2 commits intoJun 28, 2026
Merged
Conversation
asawicki
commented
Jun 28, 2026
Collaborator
…ommit writes Expose the database connection the transactional outbox middleware pins for the in-flight message via a new public IOutboxConnectionAccessor. A consumer DbContext can use that same connection so its business write commits single-phase with the buffered outbox messages and the inbox processed marker — one physical connection, one enlistment — instead of opening a second connection and forcing System.Transactions to escalate to a two-phase (prepared) commit. A single-phase commit is faster (no PREPARE/COMMIT PREPARED round-trip and fsync per message) and removes the PostgreSQL max_prepared_transactions requirement. Verified end-to-end against PostgreSQL with max_prepared_transactions=0: the OrderedConsumers sample processes every message with zero "55000: prepared transactions are disabled" errors and creates no prepared transactions, while per-key ordering and inbox deduplication remain intact. - TransactionalOutboxMiddleware publishes its pinned DbConnection on an AsyncLocal for the duration of the consume operation and clears it on completion, so a consumer resolved in its own DI scope (same async flow) can share it. - OutboxConnectionAccessor (internal) reads it; registered as a singleton by AddBareWireOutbox. - OrderedConsumers sample shares the outbox connection instead of opening its own. - EF package README leads with the single-commit pattern and a working example; 2PC is documented as the fallback. samples/README re-points the 2PC note to TransactionalOutbox and InboxDeduplication, which still rely on it.
asawicki
changed the base branch from
main
to
asawicki/fix/outbox-hardening-and-sample-2pc
June 28, 2026 15:18
… InboxDeduplication; drop 2PC Apply the single-commit connection-sharing pattern to the remaining outbox samples whose consumers persist business state during consume: TransactionalOutbox (TransferConsumer updates the Transfer row) and InboxDeduplication (Email/Audit consumers append a NotificationLog). Each now binds its DbContext to the connection the outbox middleware pinned for the in-flight message (IOutboxConnectionAccessor), so the business write commits single-phase with the outbox/inbox writes instead of opening a second connection and escalating to a two-phase (prepared) commit. With every outbox sample sharing the connection, no sample needs prepared transactions: the Aspire AppHost no longer sets max_prepared_transactions and the standalone-run instructions drop the -c max_prepared_transactions=100 flag. PostgreSQL runs with its default (2PC disabled). Verified end-to-end against PostgreSQL with max_prepared_transactions=0: - TransactionalOutbox: 3 transfers all reach Completed, zero "55000" errors, no prepared transactions. - InboxDeduplication: 2 payments produce 4 NotificationLogs (Audit=2, Email=2), zero "55000" errors.
Base automatically changed from
asawicki/fix/outbox-hardening-and-sample-2pc
to
main
June 28, 2026 20:51
asawicki
deleted the
asawicki/feat/outbox-single-commit-connection-sharing
branch
June 28, 2026 20:51
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.