feat(executor/local): clock time limit
All checks were successful
submodules sync / sync (push) Successful in 35s
build / build (push) Successful in 1m7s
build / trigger-build-image (push) Successful in 6s

This commit is contained in:
张泊明518370910136 2025-02-01 03:13:18 -05:00
parent 58c6d5607f
commit 98cf2c812f
GPG Key ID: D47306D7062CDA9D

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"io" "io"
"math"
"os" "os"
"os/exec" "os/exec"
"strings" "strings"
@ -16,44 +17,13 @@ import (
type Local struct{} type Local struct{}
func (e *Local) Run(cmds []stage.Cmd) ([]stage.ExecutorResult, error) { func generateResult(
var results []stage.ExecutorResult err error,
processState *os.ProcessState,
for _, cmd := range cmds { runTime time.Duration,
execCmd := exec.Command(cmd.Args[0], cmd.Args[1:]...) // #nosec G204 cmd stage.Cmd,
stdoutBuffer, stderrBuffer bytes.Buffer,
env := os.Environ() ) stage.ExecutorResult {
if len(cmd.Env) > 0 {
env = append(env, cmd.Env...)
}
execCmd.Env = env
if cmd.Stdin != nil {
if cmd.Stdin.Content != nil {
execCmd.Stdin = strings.NewReader(*cmd.Stdin.Content)
} else if cmd.Stdin.Src != nil {
file, err := os.Open(*cmd.Stdin.Src)
if err != nil {
return nil, fmt.Errorf("failed to open stdin file: %v", err)
}
defer file.Close()
execCmd.Stdin = file
}
}
var stdoutBuffer, stderrBuffer bytes.Buffer
execCmd.Stdout = &stdoutBuffer
execCmd.Stderr = &stderrBuffer
startTime := time.Now()
err := execCmd.Start()
if err != nil {
return nil, fmt.Errorf("failed to start command: %v", err)
}
err = execCmd.Wait()
endTime := time.Now()
runTime := endTime.Sub(startTime)
processState := execCmd.ProcessState
result := stage.ExecutorResult{ result := stage.ExecutorResult{
Status: stage.Status(envexec.StatusAccepted), Status: stage.Status(envexec.StatusAccepted),
ExitStatus: processState.ExitCode(), ExitStatus: processState.ExitCode(),
@ -111,7 +81,94 @@ func (e *Local) Run(cmds []stage.Cmd) ([]stage.ExecutorResult, error) {
result.Error = err.Error() result.Error = err.Error()
} }
return result
}
func (e *Local) Run(cmds []stage.Cmd) ([]stage.ExecutorResult, error) {
var results []stage.ExecutorResult
for _, cmd := range cmds {
execCmd := exec.Command(cmd.Args[0], cmd.Args[1:]...) // #nosec G204
if cmd.CPULimit > 0 && cmd.ClockLimit <= 0 {
cmd.ClockLimit = cmd.CPULimit * 2
}
env := os.Environ()
if len(cmd.Env) > 0 {
env = append(env, cmd.Env...)
}
execCmd.Env = env
if cmd.Stdin != nil {
if cmd.Stdin.Content != nil {
execCmd.Stdin = strings.NewReader(*cmd.Stdin.Content)
} else if cmd.Stdin.Src != nil {
file, err := os.Open(*cmd.Stdin.Src)
if err != nil {
return nil, fmt.Errorf("failed to open stdin file: %v", err)
}
defer file.Close()
execCmd.Stdin = file
}
}
var stdoutBuffer, stderrBuffer bytes.Buffer
execCmd.Stdout = &stdoutBuffer
execCmd.Stderr = &stderrBuffer
startTime := time.Now()
err := execCmd.Start()
if err != nil {
return nil, fmt.Errorf("failed to start command: %v", err)
}
done := make(chan error, 1)
go func() {
done <- execCmd.Wait()
}()
if cmd.ClockLimit > 0 {
var duration time.Duration
if cmd.ClockLimit > uint64(math.MaxInt64) {
duration = time.Duration(math.MaxInt64)
} else {
duration = time.Duration(cmd.ClockLimit) * time.Nanosecond // #nosec G115
}
select {
case err := <-done:
endTime := time.Now()
runTime := endTime.Sub(startTime)
result := generateResult(
err,
execCmd.ProcessState,
runTime,
cmd,
stdoutBuffer,
stderrBuffer,
)
results = append(results, result) results = append(results, result)
case <-time.After(duration):
_ = execCmd.Process.Kill()
result := stage.ExecutorResult{
Status: stage.Status(envexec.StatusTimeLimitExceeded),
Error: "",
Files: map[string]string{},
FileIDs: map[string]string{},
}
results = append(results, result)
}
} else {
err := <-done
endTime := time.Now()
runTime := endTime.Sub(startTime)
result := generateResult(
err,
execCmd.ProcessState,
runTime,
cmd,
stdoutBuffer,
stderrBuffer,
)
results = append(results, result)
}
} }
return results, nil return results, nil