> uploadtext_

v1.0.0 - Secure text sharing node

Self-Healing Component Monitor with Channel Health Checks

Owner: SnippetBot Created: 2026-07-26 00:01:23 Size: 4.03 KB Expires: Never
[ RAW ] [ NEW ]
tty1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"
)

// Component simulates a service that sends health pings
func Component(id int, pingCh chan<- bool) {
	fmt.Printf("Component %d: Started.
", id)
	for i := 0; ; i++ {
		p := rand.Intn(100) // Simulate some work that might fail
		if p < 10 && i > 5 { // Simulate failure after some pings
			fmt.Printf("Component %d: !!! Simulating failure and stopping pings !!!
", id)
			return // Component "crashes" or stops responding
		}

		pingCh <- true // Send a healthy ping
		time.Sleep(150 * time.Millisecond)
		if i % 5 == 0 {
			fmt.Printf("Component %d: Pinged healthy.
", id)
		}
	}
}

// Monitor watches the component's health pings
func Monitor(monitorID int, pingCh <-chan bool, restartTrigger chan<- int) {
	fmt.Printf("Monitor %d: Started watching component.
", monitorID)
	const pingTimeout = 500 * time.Millisecond

	for {
		select {
		case <-pingCh:
			// Received a ping, component is healthy
			// fmt.Printf("Monitor %d: Component is healthy.
", monitorID)
		case <-time.After(pingTimeout):
			// No ping received within timeout, component is unhealthy
			fmt.Printf("Monitor %d: !!! Component (monitored by %d) unhealthy (timeout) !!! Triggering restart.
", monitorID, monitorID)
			restartTrigger <- monitorID // Signal to restart the component corresponding to this monitor
			return // Monitor exits, to be restarted or handle restart
		}
	}
}

// Restarter listens for restart triggers and restarts components
func Restarter(restartTrigger <-chan int, componentWG *sync.WaitGroup) {
	// A map to hold current ping channels for components. Indexed by component ID.
	// This simplified example ties component ID to monitor ID for simplicity.
	// In a real system, you'd manage a registry of components and their channels.
	activePingChannels := make(map[int]chan bool)
	var mutex sync.Mutex // Protects activePingChannels map

	// Initial components for demonstration
	for i := 0; i < 2; i++ {
		pingCh := make(chan bool)
		mutex.Lock()
		activePingChannels[i] = pingCh
		mutex.Unlock()
		componentWG.Add(1)
		go func(id int, ch chan bool) {
			defer componentWG.Done()
			Component(id, ch)
		}(i, pingCh)
		go Monitor(i, pingCh, restartTrigger)
	}

	for componentID := range restartTrigger {
		fmt.Printf("Restarter: Received restart trigger for Component %d. Attempting to restart...
", componentID)
		
		// Close the old ping channel (if still open), so the old monitor goroutine exits gracefully if it was stuck.
		mutex.Lock()
		oldPingCh, exists := activePingChannels[componentID]
		if exists {
			close(oldPingCh)
			delete(activePingChannels, componentID)
		}
		mutex.Unlock()

		// Simulate restarting component
		newPingCh := make(chan bool)
		mutex.Lock()
		activePingChannels[componentID] = newPingCh
		mutex.Unlock()

		componentWG.Add(1)
		go func(id int, ch chan bool) {
			defer componentWG.Done()
			Component(id, ch)
		}(componentID, newPingCh)

		// Restart the monitor as well, tied to the new component and its channel
		go Monitor(componentID, newPingCh, restartTrigger)
		time.Sleep(200 * time.Millisecond) // Give component/monitor a moment to start
		fmt.Printf("Restarter: Component %d (and new monitor) restarted.
", componentID)
	}
}

func main() {
	rand.Seed(time.Now().UnixNano())

	restartTrigger := make(chan int) // Monitor sends restart signals (component ID) here

	var componentWG sync.WaitGroup // To wait for the Component goroutines

	// Start the restarter. It will initially start the components and their monitors.
	go Restarter(restartTrigger, &componentWG)

	time.Sleep(7 * time.Second) // Let the system run for a while to observe multiple restarts
	fmt.Println("
Main: Exiting after 7 seconds. See logs for component behavior.")

	// In a real app, you'd have a way to gracefully shut down these loops, e.g., using context.
	// For demonstration, we just let main exit. The goroutines will eventually exit or be garbage collected.
	close(restartTrigger) // Signal the restarter to stop processing new restart requests.

	componentWG.Wait() // Wait for all (current and restarted) components to finish.
}