如果另一个 goroutines 崩溃了,你如何保持 goroutines 运行?

How do you keep goroutines running if another one crashes?

我一直在努力寻找可以回答这个问题的东西,但我找不到任何关于它的东西。

假设我在 Go 中有一个函数是这样的:

func main() {
    // assume this wrapped in a waitgroup or something 
    // so that it doesnt exit
    go queue.ConsumeAndDoSomething()
    go api.StartServer()
}

我这里有两个 goroutine,它们做完全不同的事情,理想情况下,如果另一个 crashes/panics,一个应该保持 运行。如果队列操作失败,API 服务器应该受到影响,反之亦然。

我不确定这是否可行(或什至推荐)。有没有一种干净的方法可以做到这一点,或者整个程序应该在 goroutine 恐慌时退出?

如果您希望其他 goroutine 不受影响,则每个 goroutine 必须推迟 recover 调用以从潜在的 panic 中恢复。

而不是

go queue.ConsumeAndDoSomething()

你应该使用

go func(){
    defer func() {
            if r := recover(); r != nil {
                log.Error("goroutine paniqued: ", r)
            }
        }()
    queue.ConsumeAndDoSomething()
}() 

您必须使用内置的 recover() function to recover from panics, and you have to call it in a deferred 函数。

假设你有一个函数可能会崩溃:

func doPanic() {
    log.Println("about to panic")
    panic("test")
}

创建一个辅助函数来启动一个函数作为 goroutine “受保护”(避免恐慌):

func protect(f func()) {
    defer func() {
        if err := recover(); err != nil {
            log.Printf("Recovered: %v", err)
        }
    }()

    f()
}

并像这样使用它:

func main() {
    go protect(doPanic)

    for {
        time.Sleep(time.Second)
        fmt.Println("tick")
    }
}

此测试应用程序将输出:

2021/03/04 14:12:31 about to panic
2021/03/04 14:12:31 Recovered: test
tick
tick
tick
...

参见相关问题:Generic panic recovering in go programs