// Reload will stop the task if it's running. // To make sure the task is closed, a goroutine is set up to reprocess every second. func (t *SM) Reload() { if t.PendingClose() { log.Fatalf("Reload called while already waiting for a close") } t.blockRequests.Add(1) t.reloadRequest = time.Now() if !t.Running() { log.L("Change detected, will start task in %v", t.c.ChangeTimeout) go func() { time.Sleep(t.c.ChangeTimeout) t.Reprocess <- struct{}{} }() return } log.L("Change detected, will restart task in %v", t.c.ChangeTimeout) go t.reloadCheck() }
func (t *SM) closeTask() { var err error if !t.PastKillTime() { err = t.Task.Interrupt() } else { err = t.Task.Kill() } if err != nil { log.L("Failed to stop task: %v", err) } }
// Kill kills all child processes of pgid, since there is no way to kill a process // group in Windows. func (t *Task) Kill() error { log.V("Kill task") // In case killing all child processes fails. defer t.process.Kill() parentMap, err := loadProcessMap() if err != nil { return err } if errs := killChildProcesses(parentMap, uint32(t.process.Pid)); len(errs) > 0 { log.L("killChildProcesses errors: %v", errs) return fmt.Errorf("failed to kill child processes: %v", errs) } return nil }
// New starts the binary specified in args, and returns a Task for the process. func New(baseDir string, outFile string, errFile string, args []string) (*Task, error) { if !log.V("Starting task: %v", args) { log.L("Starting task") } cmd := exec.Command(args[0], args[1:]...) // Use a separate process group so we can kill the whole group. cmd.Dir = baseDir cmd.SysProcAttr = getSysProcAttrs() var err error if cmd.Stdout, err = getOutFile(outFile, os.Stdout); err != nil { return nil, err } if cmd.Stderr, err = getOutFile(errFile, os.Stderr); err != nil { return nil, err } stdinPipe, err := cmd.StdinPipe() if err != nil { return nil, err } if err := cmd.Start(); err != nil { return nil, fmt.Errorf("error starting command: %v", err) } pgid, err := getPgID(cmd) if err != nil { // If we cannot get the pgid, kill the process and return an error. cmd.Process.Kill() return nil, err } return &Task{ process: cmd.Process, pgid: pgid, stdinPipe: stdinPipe, }, nil }
func (p *proxy) connectPort(withRetry bool) (net.Conn, error) { const retryInterval = time.Millisecond * 200 const maxRetries = 300 numRetries := 10 if withRetry { numRetries = maxRetries } addr := fmt.Sprintf("localhost:%v", p.config.ForwardTo) var errors []error for i := 0; i < numRetries; i++ { conn, err := net.DialTimeout("tcp", addr, retryInterval) if err == nil { // connection is valid, update tryConnect if withRetry { p.tryConnect.Write(false) } return conn, nil } errors = append(errors, err) time.Sleep(retryInterval) } log.L("connectWithRetry failed, first error: %v", errors[0:1]) return nil, errors[len(errors)-1] }