mirror of
https://github.com/DeBrosOfficial/orama.git
synced 2026-03-17 20:06:59 +00:00
137 lines
3.0 KiB
Go
137 lines
3.0 KiB
Go
package cluster
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/signal"
|
|
"strconv"
|
|
"strings"
|
|
"syscall"
|
|
"time"
|
|
)
|
|
|
|
// HandleWatch handles the "orama cluster watch" command.
|
|
// It polls RQLite status and nodes at a configurable interval and reprints a summary.
|
|
func HandleWatch(args []string) {
|
|
interval := 10 * time.Second
|
|
|
|
// Parse --interval flag
|
|
intervalStr := getFlagValue(args, "--interval")
|
|
if intervalStr != "" {
|
|
secs, err := strconv.Atoi(intervalStr)
|
|
if err != nil || secs < 1 {
|
|
fmt.Fprintf(os.Stderr, "Error: --interval must be a positive integer (seconds)\n")
|
|
os.Exit(1)
|
|
}
|
|
interval = time.Duration(secs) * time.Second
|
|
}
|
|
|
|
// Set up signal handling for clean exit
|
|
sigCh := make(chan os.Signal, 1)
|
|
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
|
|
|
|
fmt.Printf("Watching cluster status (interval: %s, Ctrl+C to exit)\n\n", interval)
|
|
|
|
// Initial render
|
|
renderWatchScreen()
|
|
|
|
ticker := time.NewTicker(interval)
|
|
defer ticker.Stop()
|
|
|
|
for {
|
|
select {
|
|
case <-ticker.C:
|
|
renderWatchScreen()
|
|
case <-sigCh:
|
|
fmt.Printf("\nWatch stopped.\n")
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// renderWatchScreen clears the terminal and prints a summary of cluster state.
|
|
func renderWatchScreen() {
|
|
// Clear screen using ANSI escape codes
|
|
fmt.Print("\033[2J\033[H")
|
|
|
|
now := time.Now().Format("2006-01-02 15:04:05")
|
|
fmt.Printf("Cluster Watch [%s]\n", now)
|
|
fmt.Printf("=======================================\n\n")
|
|
|
|
// Query RQLite status
|
|
status, err := queryRQLiteStatus()
|
|
if err != nil {
|
|
fmt.Printf("RQLite: UNREACHABLE (%v)\n\n", err)
|
|
} else {
|
|
fmt.Printf("Local Node: %s\n", status.Store.NodeID)
|
|
fmt.Printf(" State: %-10s Term: %-6d Applied: %-8d Commit: %-8d\n",
|
|
strings.ToUpper(status.Store.Raft.State),
|
|
status.Store.Raft.Term,
|
|
status.Store.Raft.AppliedIndex,
|
|
status.Store.Raft.CommitIndex)
|
|
fmt.Printf(" Leader: %s\n", status.Store.Raft.Leader)
|
|
if status.Node.Uptime != "" {
|
|
fmt.Printf(" Uptime: %s\n", status.Node.Uptime)
|
|
}
|
|
fmt.Println()
|
|
}
|
|
|
|
// Query nodes
|
|
nodes, err := queryRQLiteNodes(true)
|
|
if err != nil {
|
|
fmt.Printf("Nodes: UNAVAILABLE (%v)\n\n", err)
|
|
} else {
|
|
total := len(nodes)
|
|
voters := 0
|
|
reachable := 0
|
|
for _, n := range nodes {
|
|
if n.Voter {
|
|
voters++
|
|
}
|
|
if n.Reachable {
|
|
reachable++
|
|
}
|
|
}
|
|
|
|
fmt.Printf("Cluster: %d nodes (%d voters), %d/%d reachable\n\n",
|
|
total, voters, reachable, total)
|
|
|
|
// Compact table
|
|
fmt.Printf("%-18s %-28s %-7s %-7s %-7s\n",
|
|
"ID", "ADDRESS", "VOTER", "LEADER", "UP")
|
|
fmt.Printf("%-18s %-28s %-7s %-7s %-7s\n",
|
|
strings.Repeat("-", 18),
|
|
strings.Repeat("-", 28),
|
|
strings.Repeat("-", 7),
|
|
strings.Repeat("-", 7),
|
|
strings.Repeat("-", 7))
|
|
|
|
for id, node := range nodes {
|
|
nodeID := id
|
|
if len(nodeID) > 18 {
|
|
nodeID = nodeID[:15] + "..."
|
|
}
|
|
|
|
voter := " "
|
|
if node.Voter {
|
|
voter = "yes"
|
|
}
|
|
|
|
leader := " "
|
|
if node.Leader {
|
|
leader = "yes"
|
|
}
|
|
|
|
up := "no"
|
|
if node.Reachable {
|
|
up = "yes"
|
|
}
|
|
|
|
fmt.Printf("%-18s %-28s %-7s %-7s %-7s\n",
|
|
nodeID, node.Address, voter, leader, up)
|
|
}
|
|
}
|
|
|
|
fmt.Printf("\nPress Ctrl+C to exit\n")
|
|
}
|