func()

in lambda/supervisor/local_supervisor.go [56:145]


func (s *LocalSupervisor) Exec(ctx context.Context, req *model.ExecRequest) error {
	if req.Domain != "runtime" {
		log.Debug("Exec is a no op if domain != runtime")
		return nil
	}
	command := exec.Command(req.Path, req.Args...)

	if req.Env != nil {
		envStrings := make([]string, 0, len(*req.Env))
		for key, value := range *req.Env {
			envStrings = append(envStrings, key+"="+value)
		}
		command.Env = envStrings
	}

	if req.Cwd != nil && *req.Cwd != "" {
		command.Dir = *req.Cwd
	}

	if req.ExtraFiles != nil {
		command.ExtraFiles = *req.ExtraFiles
	}

	command.Stdout = req.StdoutWriter
	command.Stderr = req.StderrWriter

	command.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}

	err := command.Start()

	if err != nil {
		return err
		// TODO Use supevisor specific error
	}

	pid := command.Process.Pid
	termination := make(chan struct{})
	s.processMapLock.Lock()
	s.processMap[req.Name] = process{
		pid:         pid,
		termination: termination,
	}
	s.processMapLock.Unlock()

	// The first freeze thaw cycle starts on Exec() at init time
	s.freezeThawCycleStart = time.Now()

	go func() {
		err = command.Wait()
		// close the termination channel to unblock whoever's blocked on
		// it (used to implement kill's blocking behaviour)
		close(termination)

		var cell int32
		var exitStatus *int32
		var signo *int32
		var exitErr *exec.ExitError

		if err == nil {
			exitStatus = &cell
		} else if errors.As(err, &exitErr) {
			if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
				if code := status.ExitStatus(); code >= 0 {
					cell = int32(code)
					exitStatus = &cell
				} else {
					cell = int32(status.Signal())
					signo = &cell
				}
			}
		}

		if signo == nil && exitStatus == nil {
			log.Error("Cannot convert process exit status to unix WaitStatus. This is unexpected. Assuming ExitStatus 1")
			cell = 1
			exitStatus = &cell
		}
		s.events <- model.Event{
			Time: uint64(time.Now().UnixMilli()),
			Event: model.EventData{
				Domain:     &req.Domain,
				Name:       &req.Name,
				Signo:      signo,
				ExitStatus: exitStatus,
			},
		}
	}()

	return nil
}