Skip to content

Commit 85c1b2b

Browse files
iteplovNickCraver
andauthored
2251: Fixes missing activation of the sub leg during initial endpoint discovery (#2268)
Fix for #2251 and #2265 ensuring subscription connections are proactively created in all cases. Co-authored-by: Nick Craver <nrcraver@gmail.com>
1 parent bff0811 commit 85c1b2b

8 files changed

Lines changed: 60 additions & 10 deletions

File tree

docs/ReleaseNotes.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
## Unreleased
44

5-
- Fix: `MOVED` with `NoRedirect` (and other non-reachable errors) should respect the `IncludeDetailInExceptions` setting
5+
- Fix: `MOVED` with `NoRedirect` (and other non-reachable errors) should respect the `IncludeDetailInExceptions` setting ([#2267 by mgravell](https://github.com/StackExchange/StackExchange.Redis/pull/2267))
6+
- Fix [#2251](https://github.com/StackExchange/StackExchange.Redis/issues/2251) & [#2265](https://github.com/StackExchange/StackExchange.Redis/issues/2265): Cluster endpoint connections weren't proactively connecting subscriptions in all cases and taking the full connection timeout to complete as a result ([#2268 by iteplov](https://github.com/StackExchange/StackExchange.Redis/pull/2268))
67

78

89
## 2.6.66

src/StackExchange.Redis/ConnectionMultiplexer.cs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -803,7 +803,15 @@ internal EndPoint[] GetEndPoints()
803803
}
804804
}
805805
// spin up the connection if this is new
806-
if (isNew && activate) server.Activate(ConnectionType.Interactive, log);
806+
if (isNew && activate)
807+
{
808+
server.Activate(ConnectionType.Interactive, log);
809+
if (server.SupportsSubscriptions)
810+
{
811+
// Intentionally not logging the sub connection
812+
server.Activate(ConnectionType.Subscription, null);
813+
}
814+
}
807815
}
808816
return server;
809817
}
@@ -1300,9 +1308,10 @@ internal async Task<bool> ReconfigureAsync(bool first, bool reconfigureAll, LogP
13001308
// Log current state after await
13011309
foreach (var server in servers)
13021310
{
1303-
log?.WriteLine($" {Format.ToString(server.EndPoint)}: Endpoint is {server.ConnectionState}");
1311+
log?.WriteLine($" {Format.ToString(server.EndPoint)}: Endpoint is (Interactive: {server.InteractiveConnectionState}, Subscription: {server.SubscriptionConnectionState})");
13041312
}
13051313

1314+
log?.WriteLine("Task summary:");
13061315
EndPointCollection? updatedClusterEndpointCollection = null;
13071316
for (int i = 0; i < available.Length; i++)
13081317
{
@@ -1388,7 +1397,7 @@ internal async Task<bool> ReconfigureAsync(bool first, bool reconfigureAll, LogP
13881397
else
13891398
{
13901399
server.SetUnselectable(UnselectableFlags.DidNotRespond);
1391-
log?.WriteLine($" {Format.ToString(server)}: Did not respond");
1400+
log?.WriteLine($" {Format.ToString(server)}: Did not respond (Task.Status: {task.Status})");
13921401
}
13931402
}
13941403

src/StackExchange.Redis/ServerEndPoint.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,8 @@ internal Exception? LastException
157157
}
158158
}
159159

160-
internal State ConnectionState => interactive?.ConnectionState ?? State.Disconnected;
160+
internal State InteractiveConnectionState => interactive?.ConnectionState ?? State.Disconnected;
161+
internal State SubscriptionConnectionState => subscription?.ConnectionState ?? State.Disconnected;
161162

162163
public long OperationCount => interactive?.OperationCount ?? 0 + subscription?.OperationCount ?? 0;
163164

tests/StackExchange.Redis.Tests/Cluster.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,4 +728,20 @@ public void MovedProfiling()
728728
}
729729
}
730730
}
731+
732+
[Fact]
733+
public void ConnectIncludesSubscriber()
734+
{
735+
using var conn = Create(keepAlive: 1, connectTimeout: 3000, shared: false);
736+
737+
var db = conn.GetDatabase();
738+
db.Ping();
739+
Assert.True(conn.IsConnected);
740+
741+
foreach (var server in conn.GetServerSnapshot())
742+
{
743+
Assert.Equal(PhysicalBridge.State.ConnectedEstablished, server.InteractiveConnectionState);
744+
Assert.Equal(PhysicalBridge.State.ConnectedEstablished, server.SubscriptionConnectionState);
745+
}
746+
}
731747
}

tests/StackExchange.Redis.Tests/CommandTimeouts.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public async Task DefaultHeartbeatTimeout()
2121
using var conn = ConnectionMultiplexer.Connect(options);
2222

2323
var pauseServer = GetServer(pauseConn);
24-
_ = pauseServer.ExecuteAsync("CLIENT", "PAUSE", 2000);
24+
var pauseTask = pauseServer.ExecuteAsync("CLIENT", "PAUSE", 2500);
2525

2626
var key = Me();
2727
var db = conn.GetDatabase();
@@ -30,6 +30,9 @@ public async Task DefaultHeartbeatTimeout()
3030
Log(ex.Message);
3131
var duration = sw.GetElapsedTime();
3232
Assert.True(duration < TimeSpan.FromSeconds(2100), $"Duration ({duration.Milliseconds} ms) should be less than 2100ms");
33+
34+
// Await as to not bias the next test
35+
await pauseTask;
3336
}
3437

3538
[Fact]
@@ -44,7 +47,7 @@ public async Task DefaultHeartbeatLowTimeout()
4447
using var conn = ConnectionMultiplexer.Connect(options);
4548

4649
var pauseServer = GetServer(pauseConn);
47-
_ = pauseServer.ExecuteAsync("CLIENT", "PAUSE", 2000);
50+
var pauseTask = pauseServer.ExecuteAsync("CLIENT", "PAUSE", 500);
4851

4952
var key = Me();
5053
var db = conn.GetDatabase();
@@ -53,5 +56,8 @@ public async Task DefaultHeartbeatLowTimeout()
5356
Log(ex.Message);
5457
var duration = sw.GetElapsedTime();
5558
Assert.True(duration < TimeSpan.FromSeconds(250), $"Duration ({duration.Milliseconds} ms) should be less than 250ms");
59+
60+
// Await as to not bias the next test
61+
await pauseTask;
5662
}
5763
}

tests/StackExchange.Redis.Tests/ConnectingFailDetection.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,4 +151,20 @@ public void ConnectsWhenBeginConnectCompletesSynchronously()
151151
ClearAmbientFailures();
152152
}
153153
}
154+
155+
[Fact]
156+
public void ConnectIncludesSubscriber()
157+
{
158+
using var conn = Create(keepAlive: 1, connectTimeout: 3000, shared: false);
159+
160+
var db = conn.GetDatabase();
161+
db.Ping();
162+
Assert.True(conn.IsConnected);
163+
164+
foreach (var server in conn.GetServerSnapshot())
165+
{
166+
Assert.Equal(PhysicalBridge.State.ConnectedEstablished, server.InteractiveConnectionState);
167+
Assert.Equal(PhysicalBridge.State.ConnectedEstablished, server.SubscriptionConnectionState);
168+
}
169+
}
154170
}

tests/StackExchange.Redis.Tests/Failover.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -295,8 +295,9 @@ public async Task SubscriptionsSurvivePrimarySwitchAsync()
295295
Log("FAILURE: B has not detected the topology change.");
296296
foreach (var server in bConn.GetServerSnapshot().ToArray())
297297
{
298-
Log(" Server" + server.EndPoint);
299-
Log(" State: " + server.ConnectionState);
298+
Log(" Server: " + server.EndPoint);
299+
Log(" State (Interactive): " + server.InteractiveConnectionState);
300+
Log(" State (Subscription): " + server.SubscriptionConnectionState);
300301
Log(" IsReplica: " + !server.IsReplica);
301302
Log(" Type: " + server.ServerType);
302303
}

tests/StackExchange.Redis.Tests/TestBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ internal virtual IInternalConnectionMultiplexer Create(
268268
{
269269
if (Output == null)
270270
{
271-
Assert.True(false, "Failure: Be sure to call the TestBase constuctor like this: BasicOpsTests(ITestOutputHelper output) : base(output) { }");
271+
Assert.True(false, "Failure: Be sure to call the TestBase constructor like this: BasicOpsTests(ITestOutputHelper output) : base(output) { }");
272272
}
273273

274274
// Share a connection if instructed to and we can - many specifics mean no sharing

0 commit comments

Comments
 (0)