From 9a16c9214f1d955dae52deb4208b8b4e398e32ce Mon Sep 17 00:00:00 2001 From: Liang Ding Date: Sun, 19 May 2019 00:45:49 +0800 Subject: [PATCH] =?UTF-8?q?:art:=20=E4=B8=8D=E9=80=9A=E8=BF=87=20timeout?= =?UTF-8?q?=20=E5=91=BD=E4=BB=A4=E6=8E=A7=E5=88=B6=E6=89=A7=E8=A1=8C?= =?UTF-8?q?=E8=B6=85=E6=97=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- output/run.go | 40 +++++++++++++++++++++++----------------- playground/run.go | 38 +++++++++++++++++++++++--------------- 2 files changed, 46 insertions(+), 32 deletions(-) diff --git a/output/run.go b/output/run.go index fe84652..7433665 100644 --- a/output/run.go +++ b/output/run.go @@ -22,6 +22,7 @@ import ( "os/exec" "path/filepath" "strings" + "time" "github.com/b3log/wide/conf" "github.com/b3log/wide/session" @@ -51,7 +52,7 @@ func RunHandler(w http.ResponseWriter, r *http.Request) { var cmd *exec.Cmd if conf.Docker { fileName := filepath.Base(filePath) - cmd = exec.Command("timeout", "-s", "9", "5", "docker", "run", "--rm", "--cpus", "0.1", "-v", filePath+":/"+fileName, conf.DockerImageGo, "/"+fileName) + cmd = exec.Command("docker", "run", "--rm", "--cpus", "0.1", "-v", filePath+":/"+fileName, conf.DockerImageGo, "/"+fileName) } else { cmd = exec.Command(filePath) curDir := filepath.Dir(filePath) @@ -88,6 +89,9 @@ func RunHandler(w http.ResponseWriter, r *http.Request) { return } + done := make(chan error) + go func() { done <- cmd.Wait() }() + channelRet["pid"] = cmd.Process.Pid // add the process to user's process set @@ -103,6 +107,7 @@ func RunHandler(w http.ResponseWriter, r *http.Request) { } } + rid := rand.Int() go func(runningId int) { defer util.Recover() @@ -147,25 +152,26 @@ func RunHandler(w http.ResponseWriter, r *http.Request) { wsChannel.Refresh() } } + }(rid) - cmd.Wait() + after := time.After(5 * time.Second) + channelRet["cmd"] = "run-done" + select { + case <-after: + cmd.Process.Kill() - // remove the exited process from user's process set - Processes.Remove(wSession, cmd.Process) + channelRet["output"] = "run program timeout in 5s\n" + case <-done: + channelRet["output"] = "\nrun program complete\n" + } - channelRet["cmd"] = "run-done" - // timeout: https://www.gnu.org/software/coreutils/manual/html_node/timeout-invocation.html - exitCode := cmd.ProcessState.ExitCode() - if 124 == exitCode || 125 == exitCode || 137 == exitCode { - channelRet["output"] = "run program timeout in 5s\n" - } else { - channelRet["output"] = "\nrun program complete\n" - } - if nil != wsChannel { - wsChannel.WriteJSON(&channelRet) - wsChannel.Refresh() - } - }(rand.Int()) + Processes.Remove(wSession, cmd.Process) + logger.Debugf("User [%s, %s] done running [id=%d, file=%s]", wSession.UserId, sid, rid, filePath) + + if nil != wsChannel { + wsChannel.WriteJSON(&channelRet) + wsChannel.Refresh() + } } // StopHandler handles request of stoping a running process. diff --git a/playground/run.go b/playground/run.go index e8809ef..c0d8863 100644 --- a/playground/run.go +++ b/playground/run.go @@ -22,6 +22,7 @@ import ( "os/exec" "path/filepath" "strings" + "time" "github.com/b3log/wide/conf" "github.com/b3log/wide/output" @@ -52,7 +53,7 @@ func RunHandler(w http.ResponseWriter, r *http.Request) { var cmd *exec.Cmd if conf.Docker { fileName := filepath.Base(filePath) - cmd = exec.Command("timeout", "-s", "9", "5", "docker", "run", "--rm", "--cpus", "0.1", "-v", filePath+":/"+fileName, conf.DockerImageGo, "/"+fileName) + cmd = exec.Command("docker", "run", "--rm", "--cpus", "0.1", "-v", filePath+":/"+fileName, conf.DockerImageGo, "/"+fileName) } else { cmd = exec.Command(filePath) curDir := filepath.Dir(filePath) @@ -90,6 +91,9 @@ func RunHandler(w http.ResponseWriter, r *http.Request) { return } + done := make(chan error) + go func() { done <- cmd.Wait() }() + channelRet["pid"] = cmd.Process.Pid // add the process to user's process set @@ -105,6 +109,7 @@ func RunHandler(w http.ResponseWriter, r *http.Request) { } } + rid := rand.Int() go func(runningId int) { defer util.Recover() @@ -149,23 +154,26 @@ func RunHandler(w http.ResponseWriter, r *http.Request) { wsChannel.Refresh() } } + }(rid) - cmd.Wait() + after := time.After(5 * time.Second) + channelRet["cmd"] = "run-done" + select { + case <-after: + cmd.Process.Kill() - // remove the exited process from user's process set - output.Processes.Remove(wSession, cmd.Process) + channelRet["output"] = "\nrun program timeout in 5s\n" + case <-done: + channelRet["output"] = "\nrun program complete\n" + } - channelRet["cmd"] = "run-done" - // timeout: https://www.gnu.org/software/coreutils/manual/html_node/timeout-invocation.html - exitCode := cmd.ProcessState.ExitCode() - if 124 == exitCode || 125 == exitCode || 137 == exitCode { - channelRet["output"] = "\nrun program timeout in 5s\n" - } - if nil != wsChannel { - wsChannel.WriteJSON(&channelRet) - wsChannel.Refresh() - } - }(rand.Int()) + output.Processes.Remove(wSession, cmd.Process) + logger.Debugf("User [%s, %s] done running [id=%d, file=%s]", wSession.UserId, sid, rid, filePath) + + if nil != wsChannel { + wsChannel.WriteJSON(&channelRet) + wsChannel.Refresh() + } } // StopHandler handles request of stoping a running process.