Skip to content

[Cluster] Add separate peer endpoints and optimistic gossip in 2.2.2 - #2201

Merged
Mathieu Tremblay (Mathos1432) merged 10 commits into
mainfrom
users/matrembl/peer-endpoints-v3
Oct 14, 2026
Merged

Mathieu Tremblay (Mathos1432) merged 10 commits into
mainfrom
users/matrembl/peer-endpoints-v3

Conversation

@Mathos1432

@Mathos1432 Mathieu Tremblay (Mathos1432) commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Why is this change being made?

Allow separate advertised client and peer endpoints while preserving rolling upgrades with shared endpoints.

Fixes #2107

What changed?

  • Configuration options, defaults, and StoreWrapper: add cluster-address and nullable cluster-port, with dedicated peer-port validation.
  • ClusterConfig and worker initialization: persist both endpoint pairs in format version two, apply configured endpoints during recovery and reset, and calculate peer endpoints before retry loops.
  • GossipVersionNegotiation and 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.
  • Cluster reporting and command handlers: return client endpoints in discovery, redirects, replication reports, and failover errors. Accept known client or peer endpoints for REPLICAOF and FAILOVER TO, using peer endpoints for internal connections.
  • Cluster tests: cover endpoint discovery, replication, failover, migration, recovery, reset, port validation, negotiation concurrency, reconnects and failures, simulated future-version requests, highest-supported replies with separate endpoints, repeated offers, supported retries, and connection-state preservation. Historical-server tests require a supplied executable.
  • Version.props and 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 the nodes.conf backup and downgrade warning for upgrades to 2.2.0 or later.

How was this validated?

@Mathos1432
Mathieu Tremblay (Mathos1432) force-pushed the users/matrembl/peer-endpoints-v3 branch from 81cfd88 to f0852c3 Compare October 8, 2026 20:09
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.
@Mathos1432
Mathieu Tremblay (Mathos1432) force-pushed the users/matrembl/peer-endpoints-v3 branch from f0852c3 to 75cb801 Compare October 8, 2026 20:10
@Mathos1432
Mathieu Tremblay (Mathos1432) marked this pull request as ready for review October 8, 2026 20:12
Copilot AI balanced review requested due to automatic review settings October 8, 2026 20:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ðŸŸĄ 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.

Comment thread test/cluster/Garnet.test.cluster/ClusterPeerEndpointClientTests.cs
Comment thread libs/host/Configuration/Options.cs
@vazois

Copy link
Copy Markdown
Contributor

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:

  1. INFO/ROLE break the documented invariant. Docs say clients only receive client endpoints, but INFO replication ( master_host / slaveN ) and ROLE return the peer endpoint — also diverging from Redis. These are display-only; connection logic reads config directly, so they can safely use a client accessor. Worth a test (default config has client==peer, so untested today).

  2. Breaking upgrade is avoidable?  OutboundGossipVersion  Min→Max forces unconditional v2 send. Since the reply path already negotiates  gossipVersion , per-peer negotiation could preserve v1 interop. Intentional tradeoff?

  3. Minor: dropped announce↔listen validation silently advertises typos;  GetClusterPeerEndpoint()  opens a UDP socket per CAS iteration; failover error string leaks a peer endpoint to clients.

@Mathos1432 Mathieu Tremblay (Mathos1432) changed the title [Cluster] Add separate peer endpoints in Garnet 3.0.0 (breaking) [Cluster] Add separate peer endpoints and optimistic gossip in 2.3.0 Oct 13, 2026
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
@Mathos1432 Mathieu Tremblay (Mathos1432) changed the title [Cluster] Add separate peer endpoints and optimistic gossip in 2.3.0 [Cluster] Add separate peer endpoints and optimistic gossip in 2.2.2 Oct 14, 2026
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
@Mathos1432
Mathieu Tremblay (Mathos1432) merged commit 456925d into main Oct 14, 2026
331 of 333 checks passed
@Mathos1432
Mathieu Tremblay (Mathos1432) deleted the users/matrembl/peer-endpoints-v3 branch October 14, 2026 22:17
Badrish Chandramouli (badrishc) added a commit that referenced this pull request Oct 15, 2026
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
Badrish Chandramouli (badrishc) added a commit that referenced this pull request Oct 19, 2026
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
Badrish Chandramouli (badrishc) added a commit that referenced this pull request Oct 21, 2026
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
Badrish Chandramouli (badrishc) added a commit that referenced this pull request Oct 22, 2026
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
Badrish Chandramouli (badrishc) added a commit that referenced this pull request Oct 22, 2026
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
Badrish Chandramouli (badrishc) added a commit that referenced this pull request Oct 22, 2026
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support separate client and peer cluster endpoints

3 participants