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

标签 go

我正在尝试从 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()
}

最佳答案

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

  • 您正在生成 3 个 goroutine,但只将 1 个添加到 WaitGroup ,所以您可能犯了一个错误,或者您的代码实际上只运行了 1 个命令,其他 2 个不会运行。如果要 3 个,请将 3 个添加到 WaitGroup 。

  • 我在 go 文档中找不到 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

关于go - 在 goroutine 中使用 cmd.Command 启动 Web 服务器,应用程序终止时进程不会关闭,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53842344/

相关文章:

windows - 如何在 Windows 系统上测试 App Engine 项目?

go - 如何从文件中读取 RSA key

go - 如何在 Go 中没有目录文件夹的情况下将文件压缩为 .zip

pointers - 我如何在 Go 中做一个文字 *int64?

http - 如何在golang中使用运行时错误?

go - 访问字符串的原始字节

sql - 我在 golang 中的 Postgres 查询有什么问题(LIKE 匹配)

go - 检查golang中的 slice 类型

google-app-engine - 是否可以从 Go 运行时使用 Python 的 Datastore 属性类?

javascript - 如何在 Golang 中使用 JQuery 数据表?