feat(executor/local): clock time limit
This commit is contained in:
		
							parent
							
								
									58c6d5607f
								
							
						
					
					
						commit
						98cf2c812f
					
				|  | @ -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 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user