woj-server/internal/service/runner/exec.go

110 lines
2.1 KiB
Go
Raw Normal View History

2024-01-06 16:06:53 +08:00
package runner
import (
"context"
"errors"
"fmt"
"git.0x7f.app/WOJ/woj-server/pkg/file"
"git.0x7f.app/WOJ/woj-server/pkg/utils"
"os"
"os/exec"
"time"
)
func (s *service) execute(exe string, args ...string) error {
cmd := exec.Command(exe, args...)
cmd.Dir = Prefix
if s.verbose {
cmd.Stdout = os.Stderr
cmd.Stderr = os.Stderr
}
return cmd.Run()
}
type executeArgs struct {
exe string
args []string
timeout time.Duration
kill func() error
output *os.File
limit int64
}
func (s *service) executeTimeout(arg *executeArgs) error {
ctx, cancel := context.WithTimeout(context.Background(), arg.timeout)
defer cancel()
cmd := exec.CommandContext(ctx, arg.exe, arg.args...)
cmd.Dir = Prefix
if arg.kill != nil {
cmd.Cancel = arg.kill
}
if s.verbose && arg.output == nil {
cmd.Stdout = os.Stderr
cmd.Stderr = os.Stderr
} else if arg.output != nil {
if arg.limit == 0 {
cmd.Stdout = arg.output
cmd.Stderr = arg.output
} else {
lw := &file.LimitedWriter{
File: arg.output,
Limit: arg.limit,
}
cmd.Stdout = lw
cmd.Stderr = lw
}
}
err := cmd.Start()
if err != nil {
return err
}
err = cmd.Wait()
// make sure the process is killed
_ = cmd.Process.Kill()
if errors.Is(ctx.Err(), context.DeadlineExceeded) {
return fmt.Errorf("command timed out")
}
return err
}
type podmanArgs struct {
executeArgs
memory string
}
func (s *service) podmanRun(arg *podmanArgs) error {
name := fmt.Sprintf("woj-%d-%s", time.Now().UnixNano(), utils.RandomString(8))
execArgs := &executeArgs{
exe: "podman",
output: utils.If(arg.output == nil, os.Stderr, arg.output),
limit: utils.If(arg.limit == 0, 4*1024, arg.limit),
timeout: utils.If(arg.timeout == 0, 10*time.Second, arg.timeout),
kill: func() error {
if arg.kill != nil {
_ = arg.kill()
}
return s.execute("podman", "kill", name)
},
}
args := []string{
"run",
"--rm",
"--name", name,
"--memory", utils.If(arg.memory == "", "256m", arg.memory),
}
args = append(args, arg.args...)
execArgs.args = args
return s.executeTimeout(execArgs)
}