我试图从我的程序中创建的go例程中捕捉崩溃/恐慌,以便将它们发送到我的崩溃错误报告服务器(如Sentry/Raygun)
例如,
func main() {
go func() {
// Get this panic
panic("Go routine panic")
}()
}
做这件事的惯用方法是什么?
您必须将一些代码“注入”到作为新goroutine启动的函数中:您必须调用一个延迟函数,在该函数中调用recover()
。这是从恐慌状态中恢复的唯一方法。参见相关内容:为什么'defer recovery()'不能抓住恐慌?
例如:
go func() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Caught:", r)
}
}()
panic("catch me")
}()
这将输出(在围棋游乐场上试试):
Caught: catch me
func main() {
go func() {
defer logger()
panic("catch me")
}()
time.Sleep(time.Second)
}
func logger() {
if r := recover(); r != nil {
fmt.Println("Caught:", r)
}
}
还有一个更方便甚至更紧凑的解决方案是创建一个实用函数,一个接收函数并负责恢复的“包装器”。
这是它的样子:
func wrap(f func()) {
defer func() {
if r := recover(); r != nil {
fmt.Println("Caught:", r)
}
}()
f()
}
现在使用它甚至更简单:
go wrap(func() {
panic("catch me")
})
go wrap(func() {
panic("catch me too")
})
Caught: catch me
Caught: catch me too
请注意,启动实际的goroutine发生在wrap()
之外。这使调用方可以选择是否需要新的goroutine,只需在wrap()
调用前缀go
。通常这种方法在围棋中是首选的。这允许您通过将任意函数传递给wrap()
来执行这些函数,并且它将“保护”其执行(通过从panics中恢复、正确地记录/报告它),即使您不希望在新的goroutine中并发运行它。
问题内容: 在defer函数中,我想查看一次恢复调用是否会产生非nil值(不恢复) 可能吗? 问题答案: 那确切的事情是不可能的。您可能只想重新恐慌,就像在其他语言中重新引发异常一样。
问题内容: 我曾经认为,如果goroutine中的恐慌的调用者在恐慌之前完成,它将使其终止程序(延迟恢复没有任何帮助,因为此时还没有发生恐慌), 直到我尝试以下代码: 我发现无论调用者函数完成与否,如果goroutines开始恐慌,调用者的延迟恢复机制将无济于事。整个程序仍然无效。 所以为什么?理论上,调用者功能仍在运行。当出现紧急情况时,调用者的延迟功能应起作用(包括恢复)。 问题答案: 该规范
我正在学习围棋,我试图理解如何正确处理来自外部包的恐慌。 调用doFoo方法会使服务器崩溃,我认为这是正确的行为,因为应用程序现在处于受损状态。最好是崩溃,然后通过某个负载均衡器将后续请求转发到不同的进程。但是,我的api服务器可能还在为其他客户机服务,它可能在维护websockets,而且我可能还想在这里返回一个500错误。 来自nodejs,我习惯了处理未捕获的同步异常和处理未捕获的异步异常的
作为一个新的围棋爱好者,试图使用围棋的错误处理方式。明确地说--我喜欢例外。 我有一个服务器,它接受一个连接,处理一组请求并答复它们。我发现我可以做 在深层处理代码中 null 我觉得答案是“是的,它可以工作”,可以在您自己的代码中使用,但panic不应该被用于更广泛用途的库使用。库的标准和礼貌的行为方式是通过错误返回