想想一个大型项目,它处理由自己的goroutine处理的大量并发请求。碰巧代码中存在一个错误,其中一个请求会因为nil引用而引起恐慌。
在Java,C#和许多其他语言中,这最终会导致异常停止请求,而不会对其他健康请求造成任何伤害。在go中,这会使整个程序崩溃。
AFAIK,我必须为每一个新的例程创建recover()
。这是阻止整个程序崩溃的唯一方法吗?
更新:为每个gorouting创建添加recover()
调用似乎没问题。第三方图书馆怎么样?如果第三方创建没有recover()
安全网的goroutines,似乎没有什么可做的。
答案 0 :(得分:1)
如果你去推迟恢复,我建议花一些时间来确保收集到明确的错误信息,并提供足够的信息以便迅速采取行动。
将恐慌消息写入stderr / stdout并不是很好,因为很难找到问题所在。根据我的经验,最好的方法是花一点时间让Go程序以合理的方式处理错误。来自" github.com/pkg/errors" errors.Wrap
例如,允许您包装所有错误并获得堆栈跟踪。
恢复恐慌通常是必要的恶魔。就像你说的那样,仅仅因为一个请求引起了恐慌而导致整个程序崩溃并不理想。在大多数情况下,恢复恐慌不会反击,但程序可能最终处于未定义的不可恢复状态,只有手动重启才能修复。话虽这么说,我在这种情况下的建议是确保你的Go程序暴露出一种创建核心转储的方法。
以下是当SIGQUIT发送到Go程序时如何将核心转储编写到stderr(例如kill pid -QUIT
)
go func() {
// Based on answers to this stackoverflow question:
// https://stackoverflow.com/questions/19094099/how-to-dump-goroutine-stacktraces
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGQUIT)
for {
<-sigs
fmt.Fprintln(os.Stderr, "=== received SIGQUIT ===")
fmt.Fprintln(os.Stderr, "*** goroutine dump...")
var buf []byte
var bufsize int
var stacklen int
// Create a stack buffer of 1MB and grow it to at most 100MB if
// necessary
for bufsize = 1e6; bufsize < 100e6; bufsize *= 2 {
buf = make([]byte, bufsize)
stacklen = runtime.Stack(buf, true)
if stacklen < bufsize {
break
}
}
fmt.Fprintln(os.Stderr, string(buf[:stacklen]))
fmt.Fprintln(os.Stderr, "*** end of dump")
}
}()
答案 1 :(得分:0)
没有恢复功能你无法处理恐慌,一个好的做法是使用类似功能的中间件来保护你的安全功能,结帐这个片段
{{3}}