diff options
Diffstat (limited to 'cli/internal/process/manager.go')
| -rw-r--r-- | cli/internal/process/manager.go | 120 |
1 files changed, 0 insertions, 120 deletions
diff --git a/cli/internal/process/manager.go b/cli/internal/process/manager.go deleted file mode 100644 index 0488a29..0000000 --- a/cli/internal/process/manager.go +++ /dev/null @@ -1,120 +0,0 @@ -package process - -import ( - "errors" - "fmt" - "os" - "os/exec" - "sync" - "time" - - "github.com/hashicorp/go-hclog" -) - -// ErrClosing is returned when the process manager is in the process of closing, -// meaning that no more child processes can be Exec'd, and existing, non-failed -// child processes will be stopped with this error. -var ErrClosing = errors.New("process manager is already closing") - -// ChildExit is returned when a child process exits with a non-zero exit code -type ChildExit struct { - ExitCode int - Command string -} - -func (ce *ChildExit) Error() string { - return fmt.Sprintf("command %s exited (%d)", ce.Command, ce.ExitCode) -} - -// Manager tracks all of the child processes that have been spawned -type Manager struct { - done bool - children map[*Child]struct{} - mu sync.Mutex - doneCh chan struct{} - logger hclog.Logger -} - -// NewManager creates a new properly-initialized Manager instance -func NewManager(logger hclog.Logger) *Manager { - return &Manager{ - children: make(map[*Child]struct{}), - doneCh: make(chan struct{}), - logger: logger, - } -} - -// Exec spawns a child process to run the given command, then blocks -// until it completes. Returns a nil error if the child process finished -// successfully, ErrClosing if the manager closed during execution, and -// a ChildExit error if the child process exited with a non-zero exit code. -func (m *Manager) Exec(cmd *exec.Cmd) error { - m.mu.Lock() - if m.done { - m.mu.Unlock() - return ErrClosing - } - - child, err := newChild(NewInput{ - Cmd: cmd, - // Run forever by default - Timeout: 0, - // When it's time to exit, give a 10 second timeout - KillTimeout: 10 * time.Second, - // Send SIGINT to stop children - KillSignal: os.Interrupt, - Logger: m.logger, - }) - if err != nil { - return err - } - - m.children[child] = struct{}{} - m.mu.Unlock() - err = child.Start() - if err != nil { - m.mu.Lock() - delete(m.children, child) - m.mu.Unlock() - return err - } - err = nil - exitCode, ok := <-child.ExitCh() - if !ok { - err = ErrClosing - } else if exitCode != ExitCodeOK { - err = &ChildExit{ - ExitCode: exitCode, - Command: child.Command(), - } - } - - m.mu.Lock() - delete(m.children, child) - m.mu.Unlock() - return err -} - -// Close sends SIGINT to all child processes if it hasn't been done yet, -// and in either case blocks until they all exit or timeout -func (m *Manager) Close() { - m.mu.Lock() - if m.done { - m.mu.Unlock() - <-m.doneCh - return - } - wg := sync.WaitGroup{} - m.done = true - for child := range m.children { - child := child - wg.Add(1) - go func() { - child.Stop() - wg.Done() - }() - } - m.mu.Unlock() - wg.Wait() - close(m.doneCh) -} |
