From 8b6d9ea548219a9623bdde1212385d2bddf83947 Mon Sep 17 00:00:00 2001 From: "Jeremy D. Miller" Date: Tue, 10 Feb 2026 13:58:54 -0600 Subject: [PATCH] Skip BeginTransactionAsync when transaction already exists on DbContext. Closes GH-2107 Also fix saga timeout test to use explicit activity tracking. Co-Authored-By: Claude Opus 4.6 --- ...62_test_does_not_complete_with_timeout_message.cs | 6 +++++- .../Codegen/EnrollDbContextInTransaction.cs | 12 +++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Persistence/MartenTests/Bugs/Bug_262_test_does_not_complete_with_timeout_message.cs b/src/Persistence/MartenTests/Bugs/Bug_262_test_does_not_complete_with_timeout_message.cs index c3b824788..f644be7cc 100644 --- a/src/Persistence/MartenTests/Bugs/Bug_262_test_does_not_complete_with_timeout_message.cs +++ b/src/Persistence/MartenTests/Bugs/Bug_262_test_does_not_complete_with_timeout_message.cs @@ -1,4 +1,5 @@ using IntegrationTests; +using JasperFx.Core; using Marten; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -39,7 +40,10 @@ public async Task should_work_but_doesnt() var id = Guid.NewGuid(); - await host.InvokeMessageAndWaitAsync(new SomeCommand(id)); + await host.TrackActivity() + .Timeout(30.Seconds()) + .WaitForMessageToBeReceivedAt(host) + .InvokeMessageAndWaitAsync(new SomeCommand(id)); using var session = host.Services.GetRequiredService().LightweightSession(); diff --git a/src/Persistence/Wolverine.EntityFrameworkCore/Codegen/EnrollDbContextInTransaction.cs b/src/Persistence/Wolverine.EntityFrameworkCore/Codegen/EnrollDbContextInTransaction.cs index 0399d4b3b..f2f41054f 100644 --- a/src/Persistence/Wolverine.EntityFrameworkCore/Codegen/EnrollDbContextInTransaction.cs +++ b/src/Persistence/Wolverine.EntityFrameworkCore/Codegen/EnrollDbContextInTransaction.cs @@ -2,7 +2,6 @@ using JasperFx.CodeGeneration.Frames; using JasperFx.CodeGeneration.Model; using JasperFx.Core.Reflection; -using Microsoft.EntityFrameworkCore.Storage; using Wolverine.EntityFrameworkCore.Internals; using Wolverine.Persistence; using Wolverine.Runtime; @@ -24,12 +23,9 @@ public EnrollDbContextInTransaction(Type dbContextType, IdempotencyStyle idempot _dbContextType = dbContextType; _idempotencyStyle = idempotencyStyle; - Transaction = new Variable(typeof(IDbContextTransaction), $"tx_{_dbContextType.NameInCode().Sanitize()}", this); _envelopeTransaction = new Variable(typeof(EfCoreEnvelopeTransaction), this); } - public Variable Transaction { get; } - public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) { writer.WriteLine(""); @@ -39,9 +35,11 @@ public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) writer.Write( $"await {_context.Usage}.{nameof(MessageContext.EnlistInOutboxAsync)}({_envelopeTransaction.Usage}).ConfigureAwait(false);"); - - writer.WriteComment("Start the actual database transaction"); - writer.Write($"using var {Transaction.Usage} = await {_dbContext.Usage}.Database.BeginTransactionAsync({_cancellation.Usage}).ConfigureAwait(false);"); + + writer.WriteComment("Start the actual database transaction if one does not already exist"); + writer.Write($"BLOCK:if ({_dbContext.Usage}.Database.CurrentTransaction == null)"); + writer.Write($"await {_dbContext.Usage}.Database.BeginTransactionAsync({_cancellation.Usage}).ConfigureAwait(false);"); + writer.FinishBlock(); writer.Write("BLOCK:try"); // EF Core can only do eager idempotent checks