Skip to content

Instantly share code, notes, and snippets.

@evbruno
Created February 4, 2025 14:22
Show Gist options
  • Save evbruno/e9fd31007ff373a28ca158ce846fa8dd to your computer and use it in GitHub Desktop.
Save evbruno/e9fd31007ff373a28ca158ce846fa8dd to your computer and use it in GitHub Desktop.
go - handling processes (Gemini)
# Gemini version of https://gist.github.com/evbruno/13ba9181b64eeb063079d8d1146125b4
package main
import (
"context"
"fmt"
"os"
"os/exec"
"os/signal"
"slices"
"sync"
"syscall"
"time"
)
type ProcessJob struct {
ID int
Err error
Cmd string
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel() // Ensure all processes are terminated on exit
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
processes := make(map[int]*exec.Cmd) // Store processes by PID
var wg sync.WaitGroup
fmt.Println("Hello, World!")
startProcess(ctx, &wg, processes, "bash", "-c", "sleep 10")
startProcess(ctx, &wg, processes, "bash", "-c", "sleep 15")
go func() {
wg.Wait()
cancel() // Signal completion of all processes
}()
for {
select {
case sig := <-sigChan:
fmt.Printf("\nSignal received: %v. Terminating all processes...\n", sig)
terminateAllProcesses(processes)
return // Exit gracefully after termination
case <-ctx.Done():
fmt.Println("All processes finished or terminated.")
return
}
}
}
func startProcess(ctx context.Context, wg *sync.WaitGroup, processes map[int]*exec.Cmd, name string, args ...string) {
wg.Add(1)
go func() {
defer wg.Done()
cmd := exec.CommandContext(ctx, name, args...)
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} // Ensure process group is created
cmdStr := fmt.Sprintf("%s %s", name, args)
fmt.Println("Starting:", cmdStr)
err := cmd.Start()
if err != nil {
fmt.Println("Error starting:", err)
return
}
processes[cmd.Process.Pid] = cmd // Store the command
fmt.Println("Started PID:", cmd.Process.Pid, cmdStr)
err = cmd.Wait()
if err != nil {
fmt.Println("Error waiting:", err)
} else {
fmt.Println("Finished PID:", cmd.Process.Pid, cmdStr)
}
delete(processes, cmd.Process.Pid) // Remove from the map when done
}()
}
func terminateAllProcesses(processes map[int]*exec.Cmd) {
for pid, cmd := range processes {
fmt.Printf("Stopping process (PID: %d): %v\n", pid, cmd.Args)
if cmd.Process != nil {
_ = syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) // Kill entire process group
}
}
time.Sleep(1 * time.Second) // Allow time for processes to terminate
fmt.Println("All processes terminated.")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment