Don't start an implicit EF Core transaction on ScheduleAsync for a Wolverine-mapped DbContext (closes #3121)#3122
Merged
jeremydmiller merged 2 commits intoJun 16, 2026
Conversation
…/incoming envelopes against a Wolverine-mapped DbContext (closes #3121) EfCoreEnvelopeTransaction.PersistIncomingAsync began an explicit transaction unconditionally, before checking IsWolverineEnabled(). For a Wolverine-mapped DbContext the envelope is just tracked via DbContext.Add and flushed inside SaveChangesAsync's own implicit transaction, so the explicit transaction was unnecessary — and it made IDbContextOutbox.ScheduleAsync start a transaction the caller never asked for, while PublishAsync (PersistOutgoingAsync) did not. This asymmetry was an oversight: commit 5af99ae ("Outbox behavior alignment with EF Core transaction model") moved the unconditional BeginTransactionAsync out of both PersistOutgoingAsync overloads into their raw (non-mapped) branch, but left PersistIncomingAsync untouched. This applies the same alignment: the explicit transaction is now only started in the raw branch, where an ADO command must share the caller's transaction. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eager/lazy transaction (#3121) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jun 16, 2026
Merged
This was referenced Jun 23, 2026
This was referenced Jun 30, 2026
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.
Problem
For a Wolverine-mapped
DbContext,IDbContextOutbox.ScheduleAsyncstarts an explicit EF Core transaction the caller never asked for, whilePublishAsyncdoes not:Root cause
ScheduleAsyncproduces an envelope withEnvelopeStatus.Scheduled, whichIEnvelopeTransaction.PersistAsyncroutes toPersistIncomingAsync(IEnvelopeTransaction.cs:33-34).EfCoreEnvelopeTransaction.PersistIncomingAsyncbegan an explicit transaction unconditionally, before checkingIsWolverineEnabled(). But for a mapped DbContext the envelope is simply tracked viaDbContext.Add(new IncomingMessage(...))and flushed insideSaveChangesAsync's own implicit transaction — the explicit one is pure overhead.This is an oversight from a prior refactor, not a deliberate tradeoff. Commit
5af99ae93("Outbox behavior alignment with EF Core transaction model") moved the unconditionalBeginTransactionAsyncout of bothPersistOutgoingAsyncoverloads into their raw (non-mapped) branch — but leftPersistIncomingAsyncuntouched. That's the entire asymmetry the reporter sees.Fix
Apply the same alignment to
PersistIncomingAsync: only begin an explicit transaction in the raw / non-IsWolverineEnabledbranch (where an ADO command must share the caller's transaction). The mapped branch just tracks the entity, exactly likePersistOutgoingAsync. One method; no API change.The two other callers are unaffected:
TryMakeEagerIdempotencyCheckAsyncbegins its own explicit transaction (EfCoreEnvelopeTransaction.cs:140-143).CommitAsync's handled-idempotency insert already relied on a laterSaveChangesto flush the trackedAdd, not on this forced transaction.Tests
persisting_against_mapped_dbcontext_does_not_start_an_explicit_transaction— asserts that persisting a scheduled/incoming and an outgoing envelope against a Wolverine-mapped DbContext leavesDatabase.CurrentTransactionnull.end_to_end_efcore_persistenceclass + eager-idempotency tests (23 total) remain green, confirming the raw-mode persistence and idempotency paths are unaffected.🤖 Generated with Claude Code