Skip to content

Bug: initCluster forgets newly-met nodes that are still in disconnected state after CLUSTER MEET #402

Description

@aishyandapalli

Description

In initCluster() (internal/controller/valkey_controller.go), the operator executes CLUSTER MEET for all connected nodes and then immediately iterates over CLUSTER NODES output to forget any peer that appears as disconnected. This creates a race condition: nodes that were just introduced via CLUSTER MEET may not have completed the handshake yet and still appear as disconnected in the CLUSTER NODES output. The operator then issues CLUSTER FORGET on those very same nodes it just met, effectively undoing the meet.

Root Cause

The upstream code in initCluster does the following back-to-back with no delay or safeguard:

  1. Meet all peers (lines 522–537):
for _, node := range connectedNodes {
    for _, peer := range connectedNodes {
        if node == peer { continue }
        node.client.Do(ctx, node.client.B().ClusterMeet().Ip(peer.ip).Port(int64(peer.port)).Build())
    }
}
  1. Forget disconnected peers (lines 539–573):
for _, shard := range cluster.shards {
    for _, node := range shard.nodes {
        info, _ := node.client.Do(ctx, node.client.B().ClusterNodes().Build()).ToString()
        for _, line := range strings.Split(info, "\n") {
            // ...parse peerId and connected status...
            if connected == "disconnected" {
                node.client.Do(ctx, node.client.B().ClusterForget().NodeId(peerId).Build())
            }
        }
    }
}

CLUSTER MEET is asynchronous — the Valkey gossip protocol needs time to complete the handshake. When CLUSTER NODES is queried immediately after, newly-met nodes may still report link-status as disconnected. The forget loop then removes them, causing:

  • Nodes to be repeatedly met and forgotten on every reconciliation cycle.
  • Cluster formation to stall or fail entirely, especially under network latency or high load.
  • Flapping cluster topology that never converges.

Impact

  • Cluster bootstrap failures: New clusters may never fully form because nodes keep getting forgotten before the handshake completes.
  • Replica loss: Replica nodes (which are not flagged master) are particularly vulnerable since the forget loop explicitly skips master-flagged nodes but not replicas that are still handshaking.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions