package models import ( "context" "fmt" "os" "os/exec" "strings" "time" ) type SupervisorProcess struct { Name string `json:"name"` ExecutePath string `json:"executePath"` WorkingDirectory string `json:"workingDirectory,omitempty"` StartDelay int `json:"startDelay,omitempty"` Priority int `json:"priority,omitempty"` Arguments []string `json:"arguments,omitempty"` process *exec.Cmd `json:"-"` cancel *context.CancelFunc `json:"-"` Running bool `json:"-"` } func (p *SupervisorProcess) Start() error { if p.process != nil && p.process.Process != nil { return fmt.Errorf("process %s already running", p.Name) } ctx, cancel := context.WithCancel(context.Background()) p.cancel = &cancel var args []string for _, arg := range p.Arguments { fields := strings.Fields(arg) args = append(args, fields...) } cmd := exec.CommandContext(ctx, p.ExecutePath, args...) cmd.Dir = p.WorkingDirectory cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr p.process = cmd time.Sleep(time.Duration(p.StartDelay) * time.Millisecond) if err := cmd.Start(); err != nil { return fmt.Errorf("failed to start process %s: %w", p.Name, err) } go func() { defer func() { p.Running = false }() p.Running = true err := cmd.Wait() if err != nil { fmt.Printf("Process %s exited with error: %v\n", p.Name, err) } else { fmt.Printf("Process %s exited successfully\n", p.Name) } }() return nil } func (p *SupervisorProcess) Stop() error { defer func() { p.Running = false }() if p.process == nil || p.process.Process == nil { return fmt.Errorf("process %s is not running", p.Name) } // Cancel the context if p.cancel != nil { (*p.cancel)() } err := p.process.Process.Kill() if err != nil { return fmt.Errorf("failed to kill process %s: %w", p.Name, err) } p.process = nil p.cancel = nil fmt.Printf("Process %s stopped.\n", p.Name) return nil }