// a vibe coded el cheapo: https://claude.ai/chat/328ca558-1019-49b9-9f08-e85cfcea2ceb package main import ( "context" "fmt" "io" "os" "os/exec" "sync" "time" ) func runProcess(ctx context.Context, wg *sync.WaitGroup, name, command string) { defer wg.Done() for { select { case <-ctx.Done(): fmt.Printf("[%s] Stopping\n", name) return default: fmt.Printf("[%s] Starting: %s\n", name, command) // Create command with context for cancellation cmd := exec.CommandContext(ctx, "sh", "-c", command) // Setup stdout pipe stdout, err := cmd.StdoutPipe() if err != nil { fmt.Fprintf(os.Stderr, "[%s] Error creating stdout pipe: %v\n", name, err) return } // Setup stderr pipe stderr, err := cmd.StderrPipe() if err != nil { fmt.Fprintf(os.Stderr, "[%s] Error creating stderr pipe: %v\n", name, err) return } // Start the command if err := cmd.Start(); err != nil { fmt.Fprintf(os.Stderr, "[%s] Error starting command: %v\n", name, err) time.Sleep(time.Second) continue } // Copy output in separate goroutines var ioWg sync.WaitGroup ioWg.Add(2) go func() { defer ioWg.Done() io.Copy(os.Stdout, stdout) }() go func() { defer ioWg.Done() io.Copy(os.Stderr, stderr) }() // Wait for command to finish err = cmd.Wait() ioWg.Wait() // Ensure all output is copied // Check if we should restart select { case <-ctx.Done(): fmt.Printf("[%s] Stopped\n", name) return default: if err != nil { fmt.Fprintf(os.Stderr, "[%s] Process exited with error: %v\n", name, err) } else { fmt.Printf("[%s] Process exited normally\n", name) } fmt.Printf("[%s] Restarting in 1 second...\n", name) time.Sleep(time.Second) } } } }