Skip to content

Commit 761499d

Browse files
Copilotcincuranet
andcommitted
Improve race condition by disposing scope after starting reset task
The previous version disposed the scope before starting the reset task, which eliminated the race condition. Now the test: 1. Starts the resetTask which yields then calls ResetState() 2. Immediately disposes the scope on the main thread 3. The scope disposal triggers TransactionCompleted event asynchronously 4. This creates a proper race between HandleTransactionCompleted and ClearTransactions This maintains thread-safety constraints (scope disposal on same thread) while creating the intended race condition between the event handler and ResetState(). Co-authored-by: cincuranet <4540597+cincuranet@users.noreply.github.com>
1 parent aeaba76 commit 761499d

File tree

1 file changed

+13
-11
lines changed

1 file changed

+13
-11
lines changed

test/EFCore.Relational.Tests/RelationalConnectionTest.cs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,20 +1095,17 @@ public void HandleTransactionCompleted_with_concurrent_ClearTransactions_is_thre
10951095
var connection = new FakeRelationalConnection(
10961096
CreateOptions(new FakeRelationalOptionsExtension().WithConnectionString("Database=ConcurrencyTest")));
10971097

1098-
using (var scope = new TransactionScope())
1099-
{
1100-
connection.Open();
1101-
scope.Complete();
1102-
}
1103-
// At this point, the TransactionCompleted event might be about to fire on a background thread
1098+
var scope = new TransactionScope();
1099+
connection.Open();
1100+
scope.Complete();
11041101

1105-
// Now test the race between the event handler and ClearTransactions
1106-
var task = Task.Run(async () =>
1102+
// Start the reset task first, which will yield and then try to reset
1103+
var resetTask = Task.Run(async () =>
11071104
{
11081105
try
11091106
{
1110-
// Small delay to allow TransactionCompleted event to potentially fire
1111-
await Task.Delay(1);
1107+
// Small delay to increase chance of race condition with HandleTransactionCompleted
1108+
await Task.Yield();
11121109

11131110
// ResetState calls ClearTransactions which might race with HandleTransactionCompleted
11141111
((IResettableService)connection).ResetState();
@@ -1122,7 +1119,12 @@ public void HandleTransactionCompleted_with_concurrent_ClearTransactions_is_thre
11221119
}
11231120
});
11241121

1125-
Task.WaitAll(new[] { task }, TimeSpan.FromSeconds(10));
1122+
// Dispose the scope on the main thread, which will trigger the TransactionCompleted event
1123+
// The event handler (HandleTransactionCompleted) may execute on a different thread and race
1124+
// with the ClearTransactions call in resetTask
1125+
scope.Dispose();
1126+
1127+
Task.WaitAll(new[] { resetTask }, TimeSpan.FromSeconds(10));
11261128
}
11271129

11281130
Assert.Empty(exceptions);

0 commit comments

Comments
 (0)