package consensus import ( "log" "os" "strings" "sync" "time" ) type LivenessMonitor struct { Peers []string Status map[string]bool Mu sync.RWMutex SelfID string Transport *HTTPTransport } func NewLivenessMonitor(transport *HTTPTransport) *LivenessMonitor { peersEnv := os.Getenv("DEJO_PEERS") peers := []string{} if peersEnv != "" { peers = strings.Split(peersEnv, ",") } status := make(map[string]bool) for _, peer := range peers { status[peer] = true } return &LivenessMonitor{ Peers: peers, Status: status, Transport: transport, SelfID: os.Getenv("NODE_ID"), } } func (l *LivenessMonitor) Start() { interval := 5 * time.Second if val := os.Getenv("DEJO_LIVENESS_INTERVAL"); val != "" { if d, err := time.ParseDuration(val); err == nil { interval = d } } ticker := time.NewTicker(interval) go func() { for range ticker.C { l.checkPeers() } }() } func (l *LivenessMonitor) checkPeers() { for _, peer := range l.Peers { err := l.Transport.PingPeer(peer) l.Mu.Lock() if err != nil { if l.Status[peer] { log.Println("⚠️ Peer", peer, "está OFFLINE") } l.Status[peer] = false } else { if !l.Status[peer] { log.Println("✅ Peer", peer, "voltou ONLINE") } l.Status[peer] = true } l.Mu.Unlock() } } func (l *LivenessMonitor) IsAlive(peer string) bool { if peer == l.SelfID { return true } l.Mu.RLock() defer l.Mu.RUnlock() return l.Status[peer] }