mirror of
https://gitcode.com/JianFeeeee/webui4frpc.git
synced 2026-09-20 00:47:57 +00:00
fix: 心跳复活节点、inflight 超时重发
1. handleClusterToken:心跳到达时把发送方(前驱)标记为 alive。 之前 forwardToNext 超时把节点 MarkOffline 后就再无途径恢复, 即使下一个心跳证明它活着。心跳是 leader 侧纠正误判的唯一入口。 2. forwardToNext:遍历完所有后继才返回,不要提前 inflight.clear()。 保留 inflight 状态,让 WatchTokenLoss 超时后 StartRing 重发, 重发时 AliveSuccessor 会重新计算,心跳刚复活的节点就能被选中。 这两处补丁一起提交,形成完整的存活复活闭环。
This commit is contained in:
@ -9,6 +9,8 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@ -538,11 +540,31 @@ func (h *Handler) handleClusterToken(w http.ResponseWriter, r *http.Request) {
|
||||
// predecessor's WatchLeader heartbeat fail → MarkOffline → becomeLeader
|
||||
// → StartRing, healing the ring. Per design: "心跳拒绝应当发生在leader
|
||||
// 退出节点时,让leader上邻居意识到当前环已经没有节点了".
|
||||
//
|
||||
// 同时,心跳到达说明前驱还活着,leader 应在地自己的拓扑中把它标记为
|
||||
// alive。否则 forwardToNext 一次超时把前驱 MarkOffline 后就再没有
|
||||
// 途径恢复它——前驱明明活着,leader 却认为它 offline → AliveSuccessor
|
||||
// 找不到后继,令牌冻结在 leader 手上。心跳是 leader 侧纠正误判的唯一
|
||||
// 入口(因为心跳只有前驱发给 leader 这一条边)。
|
||||
if r.Body == nil {
|
||||
if s := h.Ring.State(); len(s.Nodes) <= 1 {
|
||||
http.Error(w, "standalone node", http.StatusConflict)
|
||||
return
|
||||
}
|
||||
// 心跳到达 = 前驱活着,标记 alive(纠正 forwardToNext 的误判)
|
||||
if host, _, err := net.SplitHostPort(r.RemoteAddr); err == nil {
|
||||
s := h.Ring.State()
|
||||
for i := range s.Nodes {
|
||||
if h, _, e := net.SplitHostPort(s.Nodes[i].Addr); e == nil && h == host {
|
||||
if !s.Nodes[i].Alive {
|
||||
log.Printf("heartbeat from %s revives it (was offline)", s.Nodes[i].ID)
|
||||
}
|
||||
s.Nodes[i].Alive = true
|
||||
s.Nodes[i].LastSeen = time.Now().Unix()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return
|
||||
}
|
||||
@ -552,6 +574,20 @@ func (h *Handler) handleClusterToken(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, "standalone node", http.StatusConflict)
|
||||
return
|
||||
}
|
||||
// 同上:心跳到达 = 前驱活着
|
||||
if host, _, err := net.SplitHostPort(r.RemoteAddr); err == nil {
|
||||
s := h.Ring.State()
|
||||
for i := range s.Nodes {
|
||||
if h, _, e := net.SplitHostPort(s.Nodes[i].Addr); e == nil && h == host {
|
||||
if !s.Nodes[i].Alive {
|
||||
log.Printf("heartbeat from %s revives it (was offline)", s.Nodes[i].ID)
|
||||
}
|
||||
s.Nodes[i].Alive = true
|
||||
s.Nodes[i].LastSeen = time.Now().Unix()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user