diff --git a/weed/command/master.go b/weed/command/master.go index 3ea8c96fc..189a38a35 100644 --- a/weed/command/master.go +++ b/weed/command/master.go @@ -224,8 +224,13 @@ func startMaster(masterOption MasterOptions, masterWhiteList []string) { if raftServer == nil { glog.Fatalf("please verify %s is writable, see https://github.com/seaweedfs/seaweedfs/issues/717: %s", *masterOption.metaFolder, err) } - // For single-master mode, initialize cluster immediately without waiting - if isSingleMaster { + // For single-master mode with a fresh log, initialize cluster immediately. + // When resuming with existing state, the server is already a member and + // will self-elect via fastResume — sending another JoinCommand would block + // because goraft's setCommitIndex returns early on JoinCommand entries, + // preventing the new entry's event from being notified when old uncommitted + // JoinCommands exist in the log. + if isSingleMaster && !raftServer.HasExistingState() { glog.V(0).Infof("Single-master mode: initializing cluster immediately") raftServer.DoJoinCommand() } diff --git a/weed/server/raft_server.go b/weed/server/raft_server.go index b42ac0671..f3b84c690 100644 --- a/weed/server/raft_server.go +++ b/weed/server/raft_server.go @@ -290,6 +290,19 @@ func recoverTopologyIdFromSnapshot(dataDir string, topo *topology.Topology) { recoverTopologyIdFromState(snap.State, topo) } +// HasExistingState returns true when the raft log already contains entries, +// indicating this server was previously joined and does not need a new +// JoinCommand on startup. +func (s *RaftServer) HasExistingState() bool { + if s.raftServer != nil { + return !s.raftServer.IsLogEmpty() + } + if s.RaftHashicorp != nil { + return s.RaftHashicorp.LastIndex() > 0 + } + return false +} + func (s *RaftServer) DoJoinCommand() { glog.V(0).Infoln("Initializing new cluster")