Skip to content

Commit ad2e69f

Browse files
Add test for multiplexer GC rooting. (#2427)
Co-authored-by: Nick Craver <[email protected]>
1 parent e8b0006 commit ad2e69f

File tree

1 file changed

+48
-0
lines changed

1 file changed

+48
-0
lines changed

tests/StackExchange.Redis.Tests/GarbageCollectionTests.cs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Threading;
23
using System.Threading.Tasks;
34
using Xunit;
45
using Xunit.Abstractions;
@@ -52,4 +53,51 @@ public async Task MuxerIsCollected()
5253
// Assert.Equal(before + 1, after);
5354
//#endif
5455
}
56+
57+
[Fact]
58+
public async Task UnrootedBackloggedAsyncTaskIsCompletedOnTimeout()
59+
{
60+
// Run the test on a separate thread without keeping a reference to the task to ensure
61+
// that there are no references to the variables in test task from the main thread.
62+
// WithTimeout must not be used within Task.Run because timers are rooted and would keep everything alive.
63+
var startGC = new TaskCompletionSource<bool>();
64+
Task? completedTestTask = null;
65+
_ = Task.Run(async () =>
66+
{
67+
using var conn = await ConnectionMultiplexer.ConnectAsync(new ConfigurationOptions()
68+
{
69+
BacklogPolicy = BacklogPolicy.Default,
70+
AbortOnConnectFail = false,
71+
ConnectTimeout = 50,
72+
SyncTimeout = 1000,
73+
AllowAdmin = true,
74+
EndPoints = { GetConfiguration() },
75+
}, Writer);
76+
var db = conn.GetDatabase();
77+
78+
// Disconnect and don't allow re-connection
79+
conn.AllowConnect = false;
80+
var server = conn.GetServerSnapshot()[0];
81+
server.SimulateConnectionFailure(SimulatedFailureType.All);
82+
Assert.False(conn.IsConnected);
83+
84+
var pingTask = Assert.ThrowsAsync<RedisConnectionException>(() => db.PingAsync());
85+
startGC.SetResult(true);
86+
await pingTask;
87+
}).ContinueWith(testTask => Volatile.Write(ref completedTestTask, testTask));
88+
89+
// Use sync wait and sleep to ensure a more timely GC.
90+
var timeoutTask = Task.Delay(5000);
91+
Task.WaitAny(startGC.Task, timeoutTask);
92+
while (Volatile.Read(ref completedTestTask) == null && !timeoutTask.IsCompleted)
93+
{
94+
ForceGC();
95+
Thread.Sleep(200);
96+
}
97+
98+
var testTask = Volatile.Read(ref completedTestTask);
99+
if (testTask == null) Assert.Fail("Timeout.");
100+
101+
await testTask;
102+
}
55103
}

0 commit comments

Comments
 (0)