Skip to content

[raft] Add and remove nodes of Raft groups - #1780

Merged
MariemBaccari merged 1 commit into
interuss:masterfrom
Orbitalize:add_remove_node
Oct 27, 2026
Merged

MariemBaccari merged 1 commit into
interuss:masterfrom
Orbitalize:add_remove_node

Conversation

@MariemBaccari

@MariemBaccari MariemBaccari commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

This PR is a follow-up to #1775 and partially addresses #1719 by implementing the Add/RemoveNode methods for consensus. If removed, a leader steps down to allow for new elections.
This completes the config change handling implementation on the consensus side. Follow-up PRs will implement the admin endpoint and CLI as well as the authentication.

Comment thread pkg/raftstore/params/params.go
Comment thread pkg/raftstore/params/params.go
Comment thread pkg/raftstore/params/params.go Outdated

cctx := confChangeContext{
ID: uuid.NewString(),
URL: peerURL,

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.

Isn't this information duplicated? I.e. once here in ConfChangeV2.Context, and once more in the inner ConfChangeSingle.Context?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

ConfChangeSingle does not have a Context field, only conf change type and node ID. Were you referring to something else ?

Comment thread pkg/raftstore/consensus/consensus.go Outdated
Comment thread pkg/raftstore/consensus/consensus.go
Comment thread pkg/raftstore/consensus/consensus.go Outdated

err = c.publishEntries(entries, snapshotInterval)
if errors.Is(err, errSelfRemoved) {
c.logger.Warn("this node was removed from the Raft group, stopping")

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.

Is this the appropriate course of action?
IIUC this means the routine will just stop but the process will keep living but doing nothing, and with no hope of recovering somehow. In that case we might as well panic?
But on the other hand, can we expect having the node being added back? If so we should probably be handling that. Probably by resetting the state to what it is right after the first start.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Handling this is I think part of #1610. Panicking when an error is "expected" seems odd doesn't it ?
When the raft consumer loop exits, #1610 aims for a graceful stop but we'll have to consider that a node could be removed from one group but not the others (e.g. removed from rid but still active in aux and scd).

And no a node that has been removed cannot be added back as is, it would have to be re-added with another node ID.

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.

but we'll have to consider that a node could be removed from one group but not the others (e.g. removed from rid but still active in aux and scd)

Right, I haven't thought of that, but that actually make the issue worse IMO.

And no a node that has been removed cannot be added back as is, it would have to be re-added with another node ID.

So we actually have another issue: right now there is only one node ID passed to the CLI, to be shared to the 3 groups. So if the node is removed from one group, it actually cannot rejoin that group without leaving the other groups too. I think we need to decouple that by having a separate node ID per group instead.

That leads me to another question, why is the node ID passed by the CLI and not automatically generated?
If passed by the CLI, and if the node ID needs to be different when the node leaves the group, that means that the CLI argument needs to be changed for the node to rejoin the group. That's an issue too (c.f. discussion on deploying in k8s environment).

Aaand that leads me to yet another question: did we address the behavior of the raft node in a cluster environment? I.e. what happens when k8s spawns multiple pods? Wouldn't we have in that case multiple nodes with the same ID running?

@MariemBaccari MariemBaccari Oct 21, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Those are good points, I'd like to take some time to reflect on this. I suggest we discuss the direction we want to take for #1802 live during tomorrow's sync, what do you think ?

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.

That's the wise thing to do :)

Comment thread pkg/raftstore/consensus/consensus.go Outdated
Comment thread pkg/raftstore/consensus/consensus.go Outdated
Comment thread pkg/raftstore/consensus/membership.go

err = c.publishEntries(entries, snapshotInterval)
if errors.Is(err, errSelfRemoved) {
c.logger.Warn("this node was removed from the Raft group, stopping")

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.

but we'll have to consider that a node could be removed from one group but not the others (e.g. removed from rid but still active in aux and scd)

Right, I haven't thought of that, but that actually make the issue worse IMO.

And no a node that has been removed cannot be added back as is, it would have to be re-added with another node ID.

So we actually have another issue: right now there is only one node ID passed to the CLI, to be shared to the 3 groups. So if the node is removed from one group, it actually cannot rejoin that group without leaving the other groups too. I think we need to decouple that by having a separate node ID per group instead.

That leads me to another question, why is the node ID passed by the CLI and not automatically generated?
If passed by the CLI, and if the node ID needs to be different when the node leaves the group, that means that the CLI argument needs to be changed for the node to rejoin the group. That's an issue too (c.f. discussion on deploying in k8s environment).

Aaand that leads me to yet another question: did we address the behavior of the raft node in a cluster environment? I.e. what happens when k8s spawns multiple pods? Wouldn't we have in that case multiple nodes with the same ID running?

@mickmis mickmis 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.

LGTM

if err != nil {
c.logger.Warn("rejecting config change", zap.String("id", cctx.ID), zap.Error(err))
// A rejected change is treated as a no-op.
c.tracker.untrack(cctx.ID, ProposalResult{Error: err})

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.

May not be within scope of this PR, but this is making me wonder: IIUC we may end up with stale proposals, right? Because Node.Propose() may drop the proposal without returning an error (if I understand the doc correctly):

	// Propose proposes that data be appended to the log. Note that proposals can be lost without
	// notice, therefore it is user's job to ensure proposal retries.

How do we deal with that?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The dropped proposals gap is tracked by #1771 but not yet addressed.

@MariemBaccari
MariemBaccari merged commit 22d9a1e into interuss:master Oct 27, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants