Skip to content

Instantly share code, notes, and snippets.

@evbruno
Created February 4, 2025 14:23
Show Gist options
  • Save evbruno/db33f3d8efde64f5c77c50b86a36da5d to your computer and use it in GitHub Desktop.
Save evbruno/db33f3d8efde64f5c77c50b86a36da5d to your computer and use it in GitHub Desktop.
go - handling processes (GPT)
# OpenAI/GPT version of https://gist.github.com/evbruno/13ba9181b64eeb063079d8d1146125b4
package main
import (
"fmt"
"os"
"os/exec"
"os/signal"
"slices"
"syscall"
"time"
)
// ProcessJob represents a running process with its ID, command, and any encountered error.
type ProcessJob struct {
id int
err error
cmd string
}
func main() {
// Channels for handling signals and process status updates.
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
doneChan := make(chan ProcessJob, 1)
startChan := make(chan int)
processes := make([]int, 0)
fmt.Println("Starting process manager...")
// Launching multiple processes
go runProcess(doneChan, startChan, "bash", "-c", "sleep 10")
go runProcess(doneChan, startChan, "bash", "-c", "sleep 15")
// Main event loop for handling signals and process updates.
for {
select {
case pid := <-startChan:
// Store the process ID
processes = append(processes, pid)
fmt.Println("Processes started:", processes)
case job := <-doneChan:
// Process completion or failure handling
if job.err != nil {
fmt.Printf("Process %d failed: %v\n", job.id, job.err)
} else {
fmt.Printf("Process %d completed: %s\n", job.id, job.cmd)
}
// Remove completed process from list
if idx := slices.Index(processes, job.id); idx != -1 {
processes = slices.Delete(processes, idx, idx+1)
}
fmt.Println("Active processes:", processes)
case <-sigChan:
// Handle termination signal (CTRL+C)
fmt.Println("\nCTRL+C received! Terminating all processes...")
terminateProcesses(processes)
}
}
}
// runProcess starts a command as a child process and reports its status.
func runProcess(done chan ProcessJob, start chan int, name string, args ...string) {
cmdStr := fmt.Sprintf("%s %s", name, args)
cmd := exec.Command(name, args...)
fmt.Println("Starting process:", cmdStr)
// Start the process
if err := cmd.Start(); err != nil {
fmt.Println("Error starting process:", err)
done <- ProcessJob{0, err, cmdStr}
return
}
// Notify that the process has started
start <- cmd.Process.Pid
fmt.Println("Process running (PID):", cmd.Process.Pid)
// Wait for process completion
err := cmd.Wait()
// Report process status
done <- ProcessJob{cmd.Process.Pid, err, cmdStr}
if err != nil {
fmt.Println("Process exited with error:", err)
} else {
fmt.Println("Process completed successfully:", cmdStr)
}
}
// terminateProcesses stops all running processes.
func terminateProcesses(pids []int) {
for _, pid := range pids {
fmt.Printf("Stopping process (PID: %d)\n", pid)
_ = syscall.Kill(-pid, syscall.SIGKILL) // Kill entire process group
}
time.Sleep(1 * time.Second) // Allow time for cleanup
fmt.Println("All processes terminated.")
os.Exit(1)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment