修复在Unix-like系统上, exec.command启动的子孙进程, 调用cmd.Process.Kill()不能结束

pull/21/merge
ouqiang 2017-05-04 21:09:59 +08:00
parent 4c07b02706
commit 14295049d2
4 changed files with 23 additions and 6 deletions

View File

@ -86,10 +86,11 @@ func Exec(sshConfig SSHConfig, cmd string) (output string, err error) {
return "", err return "", err
} }
defer session.Close() defer session.Close()
// 后台运行 // 后台运行
if sshConfig.ExecTimeout < 0 { if sshConfig.ExecTimeout < 0 {
go session.CombinedOutput(cmd) go session.CombinedOutput(cmd)
time.Sleep(3 * time.Second) time.Sleep(10 * time.Second)
return "", nil return "", nil
} }
// 不限制超时 // 不限制超时

View File

@ -10,22 +10,33 @@ import (
"github.com/Tang-RoseChild/mahonia" "github.com/Tang-RoseChild/mahonia"
"strings" "strings"
"os" "os"
"syscall"
) )
// 执行shell命令可设置执行超时时间 // 执行shell命令可设置执行超时时间
// todo Windows不能KILL掉子进程, 需特殊处理
func ExecShellWithTimeout(timeout int, command string, args... string) (string, error) { func ExecShellWithTimeout(timeout int, command string, args... string) (string, error) {
cmd := exec.Command(command, args...) cmd := exec.Command(command, args...)
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
}
// 不限制超时时间 // 后台运行
if timeout <= 0 { if timeout == -1 {
go cmd.CombinedOutput()
return "", nil
}
// 不限制超时
if timeout == 0 {
output ,err := cmd.CombinedOutput() output ,err := cmd.CombinedOutput()
return string(output), err return string(output), err
} }
d := time.Duration(timeout) * time.Second d := time.Duration(timeout) * time.Second
timer := time.AfterFunc(d, func() { timer := time.AfterFunc(d, func() {
// 超时kill进程 // 超时kill进程
cmd.Process.Kill() syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
}) })
output ,err := cmd.CombinedOutput() output ,err := cmd.CombinedOutput()
timer.Stop() timer.Stop()
@ -33,6 +44,8 @@ func ExecShellWithTimeout(timeout int, command string, args... string) (string,
return string(output), err return string(output), err
} }
// 生成长度为length的随机字符串 // 生成长度为length的随机字符串
func RandString(length int64) string { func RandString(length int64) string {
sources := []byte("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") sources := []byte("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

View File

@ -138,6 +138,9 @@ func Store(ctx *macaron.Context, form TaskForm) string {
if taskModel.NotifyStatus > 0 && taskModel.NotifyReceiverId == "" { if taskModel.NotifyStatus > 0 && taskModel.NotifyReceiverId == "" {
return json.CommonFailure("请至少选择一个接收者", err) return json.CommonFailure("请至少选择一个接收者", err)
} }
if taskModel.Protocol == models.TaskHTTP && taskModel.Timeout == -1 {
return json.CommonFailure("HTTP任务不支持后台运行", err)
}
if id == 0 { if id == 0 {
id, err = taskModel.Create() id, err = taskModel.Create()
} else { } else {

View File

@ -233,7 +233,7 @@ func createTaskLog(taskModel models.TaskHost, status models.Status) (int64, stri
taskLogModel.Status = status taskLogModel.Status = status
// SSH执行远程命令后台运行 // SSH执行远程命令后台运行
var notifyId string = "" var notifyId string = ""
if taskModel.Timeout == -1 && taskModel.Protocol == models.TaskSSH { if taskModel.Timeout == -1 {
notifyId = utils.RandString(32); notifyId = utils.RandString(32);
taskLogModel.NotifyId = notifyId; taskLogModel.NotifyId = notifyId;
} }
@ -320,7 +320,7 @@ func afterExecJob(taskModel models.TaskHost, taskResult TaskResult, taskLogId in
if taskResult.Err != nil { if taskResult.Err != nil {
taskResult.Result = taskResult.Err.Error() + "\n" + taskResult.Result taskResult.Result = taskResult.Err.Error() + "\n" + taskResult.Result
} }
if taskModel.Protocol == models.TaskSSH && taskModel.Timeout == -1 { if taskModel.Timeout == -1 {
taskResult.IsAsync = true taskResult.IsAsync = true
} }
_, err := updateTaskLog(taskLogId, taskResult) _, err := updateTaskLog(taskLogId, taskResult)