// Runtime handlers the ring engine needs, provided by the app: // - RuntimeLoad: sample this node's memory/network load; // - Claim: create the frpc worker/forward for a claimed task. package cluster import ( "context" "os" "runtime" ) // AppHandler is the app-provided bridge for ring load sampling + task claims. type AppHandler struct { // LoadFn returns (mem%, net%) — lower is more idle. LoadFn func() (memPct, netPct float64) // ClaimFn creates the forward on this node (persist + spawn worker). ClaimFn func(ctx context.Context, tk *Task) error // RevokeFn cancels the forward on this node (stop worker + drop from store). RevokeFn func(ctx context.Context, tk *Task) error } // RuntimeLoad implements Handler. func (a *AppHandler) RuntimeLoad() Load { mem, net := 0.0, 0.0 if a.LoadFn != nil { mem, net = a.LoadFn() } return Load{MemPct: mem, NetPct: net} } // Claim implements Handler. func (a *AppHandler) Claim(ctx context.Context, tk *Task) error { if a.ClaimFn == nil { return nil } return a.ClaimFn(ctx, tk) } // Revoke implements Handler. func (a *AppHandler) Revoke(ctx context.Context, tk *Task) error { if a.RevokeFn == nil { return nil } return a.RevokeFn(ctx, tk) } // SampleMemLoad returns a cheap memory-usage percentage (0..100). func SampleMemLoad() float64 { var m runtime.MemStats runtime.ReadMemStats(&m) total := m.Sys if total == 0 { return 0 } return float64(m.Alloc) / float64(total) * 100 } // SampleNetLoad is implemented in netload_linux.go for Linux and returns a // safe zero fallback on other platforms. It is kept here as a package-level // API because the ring handler injects it into RuntimeLoad. // HostID returns a stable node id (hostname; empty fallback to pid). func HostID() string { h, _ := os.Hostname() if h == "" { return "node" } return h }