From db1a4a7c59068b8edac5a494dee3f59cc11848ed Mon Sep 17 00:00:00 2001 From: easonysliu Date: Tue, 17 Mar 2026 19:13:32 +0800 Subject: [PATCH] server: update isLearner metric after cluster recovery After a learner receives a snapshot or restarts from a snapshot, the etcd_server_is_learner Prometheus metric stays at 0 because the conf change log entries that originally set it have been compacted. The metric was only updated in applyConfChange, which is never called for entries already folded into a snapshot. Fix this by setting the isLearner metric right after Recover() in both the server startup path (NewServer) and the snapshot apply path (applySnapshot). This ensures the metric reflects the member's actual learner status regardless of how the cluster state was loaded. Fixes #17175 Signed-off-by: mango766 Co-Authored-By: Claude (claude-opus-4-6) Signed-off-by: easonysliu --- server/etcdserver/server.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/server/etcdserver/server.go b/server/etcdserver/server.go index 29a45f14da79..64367f61900e 100644 --- a/server/etcdserver/server.go +++ b/server/etcdserver/server.go @@ -543,6 +543,13 @@ func NewServer(cfg config.ServerConfig) (srv *EtcdServer, err error) { cl.SetStore(st) cl.SetBackend(be) cl.Recover(api.UpdateCapability) + if m := cl.Member(id); m != nil { + if m.IsLearner { + isLearner.Set(1) + } else { + isLearner.Set(0) + } + } if cl.Version() != nil && !cl.Version().LessThan(semver.Version{Major: 3}) && !beExist { os.RemoveAll(bepath) return nil, fmt.Errorf("database file (%v) of the backend is missing", bepath) @@ -1433,6 +1440,14 @@ func (s *EtcdServer) applySnapshot(ep *etcdProgress, apply *apply) { s.cluster.Recover(api.UpdateCapability) + if m := s.cluster.Member(s.ID()); m != nil { + if m.IsLearner { + isLearner.Set(1) + } else { + isLearner.Set(0) + } + } + lg.Info("restored cluster configuration") lg.Info("removing old peers from network")