diff --git a/cmd/web.go b/cmd/web.go index ff48d4f..7a0f80c 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -111,7 +111,9 @@ func catchSignal() { s := <- c logger.Info("收到信号 -- ", s) switch s { - case syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM: + case syscall.SIGHUP: + logger.Info("收到终端断开信号, 忽略") + case syscall.SIGINT, syscall.SIGTERM: shutdown() } } diff --git a/modules/utils/utils.go b/modules/utils/utils.go index 8e2c157..5ce46f2 100644 --- a/modules/utils/utils.go +++ b/modules/utils/utils.go @@ -4,48 +4,14 @@ import ( "crypto/md5" "encoding/hex" "math/rand" - "os/exec" "time" "runtime" "github.com/Tang-RoseChild/mahonia" "strings" "os" - "syscall" + "fmt" ) - -// 执行shell命令,可设置执行超时时间 -// todo Windows不能KILL掉子进程, 需特殊处理 -func ExecShellWithTimeout(timeout int, command string, args... string) (string, error) { - cmd := exec.Command(command, args...) - cmd.SysProcAttr = &syscall.SysProcAttr{ - Setpgid: true, - } - - // 后台运行 - if timeout == -1 { - go cmd.CombinedOutput() - return "", nil - } - // 不限制超时 - if timeout == 0 { - output ,err := cmd.CombinedOutput() - return string(output), err - } - - d := time.Duration(timeout) * time.Second - timer := time.AfterFunc(d, func() { - // 超时kill进程 - syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) - }) - output ,err := cmd.CombinedOutput() - timer.Stop() - - return string(output), err -} - - - // 生成长度为length的随机字符串 func RandString(length int64) string { sources := []byte("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") @@ -122,6 +88,7 @@ func EscapeJson(s string) string { return ReplaceStrings(s, specialChars, replaceChars) } +// 判断文件是否存在及是否有权限访问 func FileExist(file string) bool { _, err := os.Stat(file) if os.IsNotExist(err) { @@ -132,4 +99,9 @@ func FileExist(file string) bool { } return true +} + +// 格式化环境变量 +func FormatUnixEnv(key, value string) string { + return fmt.Sprintf("export %s=%s; ", key, value) } \ No newline at end of file diff --git a/modules/utils/utils_test.go b/modules/utils/utils_test.go index f9a9cdd..f92401a 100644 --- a/modules/utils/utils_test.go +++ b/modules/utils/utils_test.go @@ -2,13 +2,6 @@ package utils import "testing" -func TestExecShell(t *testing.T) { - _, err := ExecShell("ls") - if err != nil { - t.Fatal(err) - } -} - func TestRandString(t *testing.T) { str := RandString(32) if len(str) != 32 { diff --git a/modules/utils/utils_unix.go b/modules/utils/utils_unix.go new file mode 100644 index 0000000..9922f74 --- /dev/null +++ b/modules/utils/utils_unix.go @@ -0,0 +1,44 @@ +// +build !windows + +package utils + +import ( + "os/exec" + "syscall" + "time" + "fmt" +) + +// 执行shell命令,可设置执行超时时间 +func ExecShellWithTimeout(timeout int, command string, args... string) (string, error) { + cmd := exec.Command(command, args...) + cmd.SysProcAttr = &syscall.SysProcAttr{ + Setpgid: true, + } + + // 后台运行 + if timeout == -1 { + go cmd.CombinedOutput() + return "", nil + } + // 不限制超时 + if timeout == 0 { + output ,err := cmd.CombinedOutput() + return string(output), err + } + + d := time.Duration(timeout) * time.Second + timer := time.AfterFunc(d, func() { + // 超时kill进程 + syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) + }) + output ,err := cmd.CombinedOutput() + timer.Stop() + + return string(output), err +} + +// 格式化环境变量 +func FormatEnv(key, value string) string { + return fmt.Sprintf("export %s=%s;", key, value) +} \ No newline at end of file diff --git a/modules/utils/utils_windows.go b/modules/utils/utils_windows.go new file mode 100644 index 0000000..4e59e8f --- /dev/null +++ b/modules/utils/utils_windows.go @@ -0,0 +1,44 @@ +// +build windows + +package utils + +import ( + "syscall" + "time" + "os/exec" + "strconv" + "fmt" +) + +// 执行shell命令,可设置执行超时时间 +func ExecShellWithTimeout(timeout int, command string, args... string) (string, error) { + cmd := exec.Command(command, args...) + // 隐藏cmd窗口 + cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} + // 后台运行 + if timeout == -1 { + go cmd.CombinedOutput() + return "", nil + } + // 不限制超时 + if timeout <= 0 { + output ,err := cmd.CombinedOutput() + return string(output), err + } + + d := time.Duration(timeout) * time.Second + timer := time.AfterFunc(d, func() { + // 超时kill进程 + exec.Command("taskkill", "/F", "/T", "/PID", strconv.Itoa(cmd.Process.Pid)).Run() + cmd.Process.Kill() + }) + output ,err := cmd.CombinedOutput() + timer.Stop() + + return string(output), err +} + +// 格式化环境变量 +func FormatEnv(key, value string) string { + return fmt.Sprintf("set %s=%s & ", key, value) +} \ No newline at end of file diff --git a/service/task.go b/service/task.go index 4f4d49d..1815558 100644 --- a/service/task.go +++ b/service/task.go @@ -310,9 +310,16 @@ func beforeExecJob(taskModel *models.TaskHost) (taskLogId int64) { } // 设置notifyId到环境变量中 if notifyId != "" { - taskModel.Command = fmt.Sprintf("export GOCRON_TASK_ID=%s;%s", notifyId, taskModel.Command) + envName := "GOCRON_TASK_ID" + if taskModel.Protocol == models.TaskSSH { + taskModel.Command = fmt.Sprintf("%s%s", utils.FormatUnixEnv(envName, notifyId), taskModel.Command) + } else { + taskModel.Command = fmt.Sprintf("%s%s", utils.FormatEnv(envName, notifyId), taskModel.Command) + } } + logger.Debugf("任务命令-%s", taskModel.Command) + return taskLogId } diff --git a/templates/task/index.html b/templates/task/index.html index 737e304..ccbc437 100644 --- a/templates/task/index.html +++ b/templates/task/index.html @@ -61,7 +61,7 @@
cron表达式: {{{.Spec}}}
执行方式: {{{if eq .Protocol 1}}} HTTP {{{else if eq .Protocol 2}}} SSH {{{else if eq .Protocol 3}}}本地命令{{{end}}}
命令:{{{.Command}}}
-超时时间:{{{if gt .Timeout 0}}}{{{.Timeout}}}秒{{{else}}}不限制{{{end}}}
+超时时间:{{{if eq .Timeout -1}}}后台运行{{{else if eq .Timeout 0}}}{{{.Timeout}}}秒{{{else}}}不限制{{{end}}}
重试次数: {{{.RetryTimes}}}
是否允许多实例运行:{{{if gt .Multi 0}}}是{{{else}}}否{{{end}}}
{{{if eq .Protocol 2}}} diff --git a/templates/task/log.html b/templates/task/log.html index eeb97ba..14a701e 100644 --- a/templates/task/log.html +++ b/templates/task/log.html @@ -72,7 +72,7 @@