Repository navigation
[Cluster] Add separate peer endpoints and optimistic gossip in 2.2.2 - #2201
Conversation
81cfd88 to
f0852c3
Compare
Add cluster-address and nullable cluster-port, separate client advertisements from peer routing, and enable configuration format version two. Set version 3.0.0 and require every existing node to run 2.2.0 or later before upgrading. Document bootstrap and upgrade requirements. Cover endpoint discovery, redirects, migration, replication, failover, recovery, and port validation with client and configuration tests.
f0852c3 to
75cb801
Compare
There was a problem hiding this comment.
ðĄ Changes recommended
The linked validation consistently fails the new replication tests in Windows cluster jobs.
1 open finding
What changed in this PR
Adds separate client-advertised and peer endpoints for Garnet clusters, with a breaking 3.0.0 protocol transition.
Changes:
- Adds peer address/port configuration and validation.
- Routes gossip, replication, failover, migration, and discovery through appropriate endpoints.
- Adds endpoint tests, upgrade guidance, and 3.0.0 versioning.
| File | Description |
|---|---|
website/âdocs/âgetting-started/âconfiguration.md |
Documents endpoint settings and staged upgrades. |
website/âdocs/âcommands/âserver.md |
Clarifies REPLICAOF endpoint behavior. |
website/âdocs/âcommands/âcluster.md |
Clarifies CLUSTER MEET reachability. |
Version.props |
Sets version 3.0.0. |
test/âstandalone/âGarnet.test/âGarnetServerConfigTests.cs |
Tests configuration and port validation. |
test/âcluster/âGarnet.test.cluster/âClusterPeerEndpointClientTests.cs |
Tests client routing and replication scenarios. |
test/âcluster/âGarnet.test.cluster/âClusterConfigTests.cs |
Tests persistence, recovery, and endpoint resolution. |
libs/âserver/âStoreWrapper.cs |
Resolves effective peer endpoints. |
libs/âserver/âServers/âServerOptions.cs |
Adds peer endpoint options. |
libs/âhost/âdefaults.conf |
Defines endpoint defaults. |
libs/âhost/âConfiguration/âOptionsValidators.cs |
Validates peer addresses and ports. |
libs/âhost/âConfiguration/âOptions.cs |
Parses and maps new settings. |
libs/âcluster/âSession/âRespClusterBasicCommands.cs |
Returns client endpoints. |
libs/âcluster/âSession/âReplicaOfCommand.cs |
Resolves client or peer targets. |
libs/âcluster/âSession/âFailoverCommand.cs |
Uses peer endpoints for failover. |
libs/âcluster/âServer/âClusterManagerWorkerState.cs |
Applies peer endpoints during initialization/reset. |
libs/âcluster/âServer/âClusterConfig.cs |
Enables format-v2 gossip and peer metadata. |
ð§ Review effort: Balanced
ðĄ Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
Nice split â gossip/merge path looks sound (conflict resolution stays config-epoch based, peer endpoints aren't part of slot ownership). A few items before merge:
|
Preserve reconnect backoff, credential refresh, and sampled gossip limits alongside connection-specific gossip negotiation. Add reconnect coverage for legacy and upgraded peers. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 792f9457-7c13-4dad-a4f0-eff79ae90a19
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 792f9457-7c13-4dad-a4f0-eff79ae90a19
Reply to unsupported gossip with a full configuration in the highest supported format without merging the payload or changing the selected connection state. Cover future-version probes, repeated offers, split endpoints, supported retries, and incompatible replies. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 792f9457-7c13-4dad-a4f0-eff79ae90a19
Rebasing onto main brings in #2230, which drops net8.0, and #2201, whose gossip publish path calls AsyncUtils.BlockingWait on a ValueTask - an overload this branch deletes. Gossip.PublishMessage reaches that call only inside an IsCompletedSuccessfully branch, so it never waits; the sibling GetOrAddAsync call three lines above already observes its result through GetResultGuarded. Use the same awaiter here. With one target framework left, the net8 leg of the pending-read allocation bound is dead and its calibration table carries a column for a runtime that is no longer built. Keep the net10 bound and the net10 numbers. The park-allocation comment loses its note about .NET 8 boxing the handler's continuation frame, which no longer describes anything this branch builds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: fd65c995-cc75-421a-ae0b-c96dc4e9bbeb
Rebasing onto main brings in #2230, which drops net8.0, and #2201, whose gossip publish path calls AsyncUtils.BlockingWait on a ValueTask - an overload this branch deletes. Gossip.PublishMessage reaches that call only inside an IsCompletedSuccessfully branch, so it never waits; the sibling GetOrAddAsync call three lines above already observes its result through GetResultGuarded. Use the same awaiter here. With one target framework left, the net8 leg of the pending-read allocation bound is dead and its calibration table carries a column for a runtime that is no longer built. Keep the net10 bound and the net10 numbers. The park-allocation comment loses its note about .NET 8 boxing the handler's continuation frame, which no longer describes anything this branch builds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: fd65c995-cc75-421a-ae0b-c96dc4e9bbeb
Rebasing onto main brings in #2230, which drops net8.0, and #2201, whose gossip publish path calls AsyncUtils.BlockingWait on a ValueTask - an overload this branch deletes. Gossip.PublishMessage reaches that call only inside an IsCompletedSuccessfully branch, so it never waits; the sibling GetOrAddAsync call three lines above already observes its result through GetResultGuarded. Use the same awaiter here. With one target framework left, the net8 leg of the pending-read allocation bound is dead and its calibration table carries a column for a runtime that is no longer built. Keep the net10 bound and the net10 numbers. The park-allocation comment loses its note about .NET 8 boxing the handler's continuation frame, which no longer describes anything this branch builds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: fd65c995-cc75-421a-ae0b-c96dc4e9bbeb
Rebasing onto main brings in #2230, which drops net8.0, and #2201, whose gossip publish path calls AsyncUtils.BlockingWait on a ValueTask - an overload this branch deletes. Gossip.PublishMessage reaches that call only inside an IsCompletedSuccessfully branch, so it never waits; the sibling GetOrAddAsync call three lines above already observes its result through GetResultGuarded. Use the same awaiter here. With one target framework left, the net8 leg of the pending-read allocation bound is dead and its calibration table carries a column for a runtime that is no longer built. Keep the net10 bound and the net10 numbers. The park-allocation comment loses its note about .NET 8 boxing the handler's continuation frame, which no longer describes anything this branch builds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: fd65c995-cc75-421a-ae0b-c96dc4e9bbeb
Rebasing onto main brings in #2230, which drops net8.0, and #2201, whose gossip publish path calls AsyncUtils.BlockingWait on a ValueTask - an overload this branch deletes. Gossip.PublishMessage reaches that call only inside an IsCompletedSuccessfully branch, so it never waits; the sibling GetOrAddAsync call three lines above already observes its result through GetResultGuarded. Use the same awaiter here. With one target framework left, the net8 leg of the pending-read allocation bound is dead and its calibration table carries a column for a runtime that is no longer built. Keep the net10 bound and the net10 numbers. The park-allocation comment loses its note about .NET 8 boxing the handler's continuation frame, which no longer describes anything this branch builds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: fd65c995-cc75-421a-ae0b-c96dc4e9bbeb
Rebasing onto main brings in #2230, which drops net8.0, and #2201, whose gossip publish path calls AsyncUtils.BlockingWait on a ValueTask - an overload this branch deletes. Gossip.PublishMessage reaches that call only inside an IsCompletedSuccessfully branch, so it never waits; the sibling GetOrAddAsync call three lines above already observes its result through GetResultGuarded. Use the same awaiter here. With one target framework left, the net8 leg of the pending-read allocation bound is dead and its calibration table carries a column for a runtime that is no longer built. Keep the net10 bound and the net10 numbers. The park-allocation comment loses its note about .NET 8 boxing the handler's continuation frame, which no longer describes anything this branch builds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: fd65c995-cc75-421a-ae0b-c96dc4e9bbeb

Why is this change being made?
Allow separate advertised client and peer endpoints while preserving rolling upgrades with shared endpoints.
Fixes #2107
What changed?
StoreWrapper: addcluster-addressand nullablecluster-port, with dedicated peer-port validation.ClusterConfigand worker initialization: persist both endpoint pairs in format version two, apply configured endpoints during recovery and reset, and calculate peer endpoints before retry loops.GossipVersionNegotiationand cluster sessions: send the latest format first. Receivers return a full configuration in their highest supported format for unsupported requests without merging them or changing the connection's selected format. Senders retry only after a valid older-format reply and cache the confirmed format until reconnect. Retain reconnect backoff and credential refresh, and reject version one when client and peer endpoints differ. Publish forwarding logs failed peer initialization and continues to healthy peers.REPLICAOFandFAILOVER TO, using peer endpoints for internal connections.Version.propsand upgrade documentation: set version 2.2.2, document negotiation and older-release behavior, allow direct rolling upgrades with unchanged shared endpoints, require every node to run 2.2.2 or later before separating endpoints, and retain thenodes.confbackup and downgrade warning for upgrades to 2.2.0 or later.How was this validated?