From 69a26a66af80522936a14de3adfc4fb0284f7f0f Mon Sep 17 00:00:00 2001 From: Alexey Zimarev Date: Wed, 19 Aug 2026 15:44:24 +0200 Subject: [PATCH 1/2] fix(test): stop Redis fixture aborting on first connection attempt The Redis test fixture connects right after the container reports ready, and the first connection attempt occasionally races the server, failing the whole fixture initialization with RedisConnectionException before any test runs. abortConnect=false makes the multiplexer keep retrying instead of aborting. Co-Authored-By: Claude Fable 5 --- .../test/Eventuous.Tests.Redis/Fixtures/IntegrationFixture.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Redis/test/Eventuous.Tests.Redis/Fixtures/IntegrationFixture.cs b/src/Redis/test/Eventuous.Tests.Redis/Fixtures/IntegrationFixture.cs index e237509d..0c37883b 100644 --- a/src/Redis/test/Eventuous.Tests.Redis/Fixtures/IntegrationFixture.cs +++ b/src/Redis/test/Eventuous.Tests.Redis/Fixtures/IntegrationFixture.cs @@ -37,7 +37,9 @@ public async Task InitializeAsync() { IDatabase GetDb() { // FLUSHDB in test teardown is an admin command; StackExchange.Redis 3.x enforces the // admin gate for raw commands issued through Execute as well. - var muxer = ConnectionMultiplexer.Connect($"{connString},allowAdmin=true"); + // abortConnect=false keeps the multiplexer retrying when the first connection attempt + // races the freshly started container. + var muxer = ConnectionMultiplexer.Connect($"{connString},allowAdmin=true,abortConnect=false"); return muxer.GetDatabase(); } From dc8545c2d865f396aef2775cabe10b546a4f3203 Mon Sep 17 00:00:00 2001 From: Alexey Zimarev Date: Wed, 19 Aug 2026 17:47:14 +0200 Subject: [PATCH 2/2] Connect the Redis test fixture asynchronously with a shared multiplexer Address the review note: replace the synchronous ConnectionMultiplexer.Connect inside InitializeAsync with an awaited ConnectAsync. Connect once and share the multiplexer across tests instead of opening a new connection per GetDatabase call, and dispose it with the fixture; abortConnect=false is preserved so the first attempt keeps retrying when it races the freshly started container. Co-Authored-By: Claude Fable 5 --- .../Fixtures/IntegrationFixture.cs | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Redis/test/Eventuous.Tests.Redis/Fixtures/IntegrationFixture.cs b/src/Redis/test/Eventuous.Tests.Redis/Fixtures/IntegrationFixture.cs index 0c37883b..b088e9dc 100644 --- a/src/Redis/test/Eventuous.Tests.Redis/Fixtures/IntegrationFixture.cs +++ b/src/Redis/test/Eventuous.Tests.Redis/Fixtures/IntegrationFixture.cs @@ -15,6 +15,7 @@ public sealed class IntegrationFixture : IAsyncInitializer, IAsyncDisposable { readonly ActivityListener _listener = DummyActivityListener.Create(); RedisContainer _redisContainer = null!; + ConnectionMultiplexer _muxer = null!; IEventSerializer Serializer { get; } = new DefaultEventSerializer(TestPrimitives.DefaultOptions); @@ -25,6 +26,14 @@ public async Task InitializeAsync() { await _redisContainer.StartAsync(); var connString = _redisContainer.GetConnectionString(); + + // FLUSHDB in test teardown is an admin command; StackExchange.Redis 3.x enforces the + // admin gate for raw commands issued through Execute as well. + // abortConnect=false keeps the multiplexer retrying when the first connection attempt + // races the freshly started container. The multiplexer is shared by all tests, as one + // connection per process is how StackExchange.Redis is meant to be used. + _muxer = await ConnectionMultiplexer.ConnectAsync($"{connString},allowAdmin=true,abortConnect=false"); + await Module.LoadModule(GetDb); GetDatabase = GetDb; @@ -34,18 +43,11 @@ public async Task InitializeAsync() { return; - IDatabase GetDb() { - // FLUSHDB in test teardown is an admin command; StackExchange.Redis 3.x enforces the - // admin gate for raw commands issued through Execute as well. - // abortConnect=false keeps the multiplexer retrying when the first connection attempt - // races the freshly started container. - var muxer = ConnectionMultiplexer.Connect($"{connString},allowAdmin=true,abortConnect=false"); - - return muxer.GetDatabase(); - } + IDatabase GetDb() => _muxer.GetDatabase(); } public async ValueTask DisposeAsync() { + _muxer.Dispose(); await _redisContainer.DisposeAsync(); _listener.Dispose(); }