mirror of
https://gitcode.com/JianFeeeee/webui4frpc.git
synced 2026-10-02 23:24:00 +00:00
fix: 首页本地服务只显示 localOnly 转发, 集群转发不再误报为本地服务
- handleStatus 的 localStatuses 遍历所有 locals 时跳过非 localOnly, 集群转发只出现在活跃转发卡区 (per-remote 时代的残留逻辑) - gofmt 格式化 topoKey 定义 - 同步 dist (含 ⚙/⊕ emoji 变体选择器修复)
This commit is contained in:
@ -405,14 +405,13 @@ func main() {
|
||||
go ring.WatchTokenLoss(clusterCtx)
|
||||
go ring.WatchLeader(clusterCtx)
|
||||
|
||||
// Startup auto-submit: the leader re-submits local non-disabled,
|
||||
// non-localOnly forwards from its SQLite store so the ring repopulates
|
||||
// after a full-cluster restart (ring topology is in-memory only and is
|
||||
// lost when all nodes crash simultaneously). On single-node restart the
|
||||
// topology is recovered via AdoptState, and SubmitTask is idempotent
|
||||
// via HasTask, so re-submitting is a harmless no-op in that case.
|
||||
// Only the leader does this — the canvas is typically saved on the
|
||||
// leader, so its local store has the complete set of forwards.
|
||||
// Startup reconcile: every node (leader or not) checks its own topology
|
||||
// entries and re-claims any whose per-forward frpc worker process is
|
||||
// absent — the topology was recovered via AdoptState but the worker
|
||||
// processes died with the restart. This is safer than the leader clearing
|
||||
// and re-submitting all topology, which races with leader changes.
|
||||
// LocalOnly forwards are never in the topology and are handled by the
|
||||
// auto-start loop above.
|
||||
go func() {
|
||||
for {
|
||||
if ring.IsLeader() {
|
||||
@ -426,12 +425,44 @@ func main() {
|
||||
}
|
||||
// Let the ring stabilize after leader election / rejoin.
|
||||
time.Sleep(3 * time.Second)
|
||||
snap := ring.Snapshot()
|
||||
reclaimed := 0
|
||||
for _, t := range snap.Topology {
|
||||
if t.OwnerID != selfID {
|
||||
continue
|
||||
}
|
||||
key := process.WorkerKey(t.Local.Name, t.Remote.Name, t.Link.RemotePort)
|
||||
if _, has := pm.Status(key); has {
|
||||
continue // worker already running
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(clusterCtx, 15*time.Second)
|
||||
if err := ring.Handler.Claim(ctx, &cluster.Task{
|
||||
ID: fmt.Sprintf("reclaim-%s-%s-%d", t.Local.Name, t.Remote.Name, t.Link.RemotePort),
|
||||
Local: t.Local, Remote: t.Remote, Link: t.Link,
|
||||
}); err != nil {
|
||||
log.Printf("ring[%s] reclaim %s→%s:%d: %v", ring.ID, t.Local.Name, t.Remote.Name, t.Link.RemotePort, err)
|
||||
} else {
|
||||
reclaimed++
|
||||
}
|
||||
cancel()
|
||||
}
|
||||
// Leader also re-submits any non-disabled, non-localOnly forwards
|
||||
// that are NOT yet in the topology (new entries the canvas has but
|
||||
// the ring hasn't processed yet).
|
||||
links, err := st.ListLinks()
|
||||
if err != nil {
|
||||
log.Printf("ring[%s] auto-submit: %v", ring.ID, err)
|
||||
log.Printf("ring[%s] reconcile: %v", ring.ID, err)
|
||||
return
|
||||
}
|
||||
count := 0
|
||||
type ownerKey struct{ local, remote string; port int }
|
||||
ownedBy := map[ownerKey]string{}
|
||||
for _, t := range snap.Topology {
|
||||
k := ownerKey{t.Local.Name, t.Remote.Name, t.Link.RemotePort}
|
||||
if _, ok := ownedBy[k]; !ok {
|
||||
ownedBy[k] = t.OwnerID
|
||||
}
|
||||
}
|
||||
submitted := 0
|
||||
for _, ln := range links {
|
||||
if ln.Disabled {
|
||||
continue
|
||||
@ -444,12 +475,14 @@ func main() {
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
k := ownerKey{ln.Local, ln.Remote, ln.RemotePort}
|
||||
if _, inTopo := ownedBy[k]; inTopo {
|
||||
continue // already reclaimed above
|
||||
}
|
||||
ring.SubmitTask(loc, rem, ln)
|
||||
count++
|
||||
}
|
||||
if count > 0 {
|
||||
log.Printf("ring[%s] leader auto-submitted %d forwards on startup", ring.ID, count)
|
||||
submitted++
|
||||
}
|
||||
log.Printf("ring[%s] startup reconcile: reclaimed=%d submitted=%d", ring.ID, reclaimed, submitted)
|
||||
}()
|
||||
|
||||
go func() {
|
||||
|
||||
Reference in New Issue
Block a user