Summary
A subscriber to IConnectionGroup.ServerMaintenanceEvent cannot tell which group member a notification came from, because the one link it needs — ConnectionGroupMember.Multiplexer — is internal.
Detail
MultiGroupMultiplexer forwards the event by attaching the subscriber's own delegate to every member:
add
{
if (AddHandler(ref _serverMaintenanceEvent, value))
{
foreach (var member in _members)
{
member.Multiplexer.ServerMaintenanceEvent += value;
}
}
}
So the sender the subscriber receives is the child ConnectionMultiplexer, not the group. The group layer itself does not react to maintenance notifications — selection is driven by health checks, circuit-breaker failures and TryFailoverTo — so deciding whether a notification concerns the connection currently carrying commands is left to the subscriber.
IConnectionGroup.ActiveMember is public and ConnectionGroupMember is a public type, but ConnectionGroupMember.Multiplexer is internal, so there is no supported way to complete the comparison:
// what a subscriber wants to write, and cannot
if (muxer is IConnectionGroup group && group.ActiveMember?.Multiplexer != sender)
{
return;
}
Why it matters
This is most acute for MOVING. It is scoped to the connection it arrived on, it names that connection's replacement, and the server does not replay it. A subscriber that cannot attribute it has two options, both wrong in one direction:
- filter on
sender identity against the multiplexer it subscribed to, and silently drop every MOVING on a group connection, losing a notice that never comes again;
- forward everything, and act on a
MOVING describing a member the cache is not currently using.
Comparing PushMaintenanceEvent.EndPoint against GetEndPoints() is the only public alternative, and it is fragile — IPEndPoint versus DnsEndPoint and normalisation differences make a mismatch drop the notification rather than over-forward it.
Suggested fix
Make ConnectionGroupMember.Multiplexer public. It is a one-line accessibility change on a type that is already public, and it makes the attribution exact without exposing anything new about the group's internals.
An alternative would be for MultiGroupMultiplexer to re-raise ServerMaintenanceEvent with itself as sender, but that loses which member the notification described, which is the information the subscriber actually needs.
Workaround in use
Reading ConnectionGroupMember.Multiplexer reflectively, with the check skipped whenever the
lookup fails so an upstream rename costs a redundant notification rather than a lost one. It works,
but it pins a library's internals from outside, which is what this issue asks to avoid.
Version
StackExchange.Redis 3.3.0.
Summary
A subscriber to
IConnectionGroup.ServerMaintenanceEventcannot tell which group member a notification came from, because the one link it needs —ConnectionGroupMember.Multiplexer— isinternal.Detail
MultiGroupMultiplexerforwards the event by attaching the subscriber's own delegate to every member:So the
senderthe subscriber receives is the childConnectionMultiplexer, not the group. The group layer itself does not react to maintenance notifications — selection is driven by health checks, circuit-breaker failures andTryFailoverTo— so deciding whether a notification concerns the connection currently carrying commands is left to the subscriber.IConnectionGroup.ActiveMemberis public andConnectionGroupMemberis a public type, butConnectionGroupMember.Multiplexerisinternal, so there is no supported way to complete the comparison:Why it matters
This is most acute for
MOVING. It is scoped to the connection it arrived on, it names that connection's replacement, and the server does not replay it. A subscriber that cannot attribute it has two options, both wrong in one direction:senderidentity against the multiplexer it subscribed to, and silently drop everyMOVINGon a group connection, losing a notice that never comes again;MOVINGdescribing a member the cache is not currently using.Comparing
PushMaintenanceEvent.EndPointagainstGetEndPoints()is the only public alternative, and it is fragile —IPEndPointversusDnsEndPointand normalisation differences make a mismatch drop the notification rather than over-forward it.Suggested fix
Make
ConnectionGroupMember.Multiplexerpublic. It is a one-line accessibility change on a type that is already public, and it makes the attribution exact without exposing anything new about the group's internals.An alternative would be for
MultiGroupMultiplexerto re-raiseServerMaintenanceEventwith itself as sender, but that loses which member the notification described, which is the information the subscriber actually needs.Workaround in use
Reading
ConnectionGroupMember.Multiplexerreflectively, with the check skipped whenever thelookup fails so an upstream rename costs a redundant notification rather than a lost one. It works,
but it pins a library's internals from outside, which is what this issue asks to avoid.
Version
StackExchange.Redis 3.3.0.