在goroutine中使用cmd.Command启动Web服务器,终止应用程序时进程不会关闭

时间:2018-12-18 23:00:23

标签: go

我正在尝试同时生成多个命令,然后在第一个任务完成时将它们全部关闭。

问题在于,有时在生成dotnet服务器并使用sudo浏览我的项目时,在应用程序终止时,生成的进程不会终止。

为什么会发生这种情况以及如何终止进程?

大概这个

func createCommand(command string) {
    var cmd *exec.Cmd
    cmd = exec.Command("/bin/bash", "-c", command)
    return cmd
}


func main() {
    commands := []string{
        "cd server1 && dotnet run", 
        "cd server2 && dotnet run",
        "sleep 10 && echo complete"
    }
    var wg sync.WaitGroup
    wg.Add(1)
    var cmds []*exec.Cmd

    defer func() {
        fmt.Println("Process clean up")
        for _, cmd := range cmds {
            cmd.Process.Kill()
        }
    }()

    for _, command := range commands {
        cmd := createCommand(command)
        cmds = append(cmds, cmd)
        go func (c string) {
            defer wg.Done()
            c.Start()
            c.Wait()
        }(cmd)
    }
    wg.Wait()
}

1 个答案:

答案 0 :(得分:1)

我不确定sudo的问题。但是您的代码存在以下问题:

  • 您正在生成3个goroutine,但仅向等待组中添加了1个,因此您可能出错了,或者您的代码实际上仅运行了1条命令,而其他2条则不会运行。如果需要3,请将3添加到等待组。

  • 我在go docs中找不到cmd.Process.Kill(),但看到了os.Process.Kill。但是,建议使用上下文取消进程。有了上下文,您的命令肯定会终止。

下面的代码演示了我的想法:

package main

import (
    "os/exec"
    "fmt"
    "sync"
    "context"
    "time"
)


func createCommand(ctx context.Context, command string) *exec.Cmd{
    return exec.CommandContext(ctx, "/bin/bash", "-c", command)
}


func main() {
    commands := []string{
        "sleep 1000000 && echo complete", 
        "sleep 1000000 && echo complete",
        "sleep 10 && echo complete",
    }
    var wg sync.WaitGroup
    wg.Add(3)
    var cmds []*exec.Cmd

    ctx, cancel := context.WithTimeout(context.Background(), 20 * time.Second)
    defer func() {
        fmt.Println("Process clean up")
        cancel()
    }()

    for _, command := range commands {
    fmt.Printf("Create command %s\n", command)
        cmd := createCommand(ctx, command)
        cmds = append(cmds, cmd)
        go func (c *exec.Cmd, name string) {
        fmt.Printf("Process command %s\n", name)
            defer wg.Done()
            c.Start()
            c.Wait()
        fmt.Printf("Finish command %s\n", name)
        }(cmd, command)
    }
    wg.Wait()
}

输出为:

Create command sleep 1000000 && echo complete
Create command sleep 1000000 && echo complete
Create command sleep 10 && echo complete
Process command sleep 10 && echo complete
Finish command sleep 10 && echo complete
Process command sleep 1000000 && echo complete
Finish command sleep 1000000 && echo complete
Process command sleep 1000000 && echo complete
Finish command sleep 1000000 && echo complete
Process clean up