How to handle panic error in Golang
ref: https://ednsquare.com/story/learn-go-panic-and-recover-in-golang------1HSVNg
func main() {
NullPointer(nil)
time.Sleep(2*time.Second)
fmt.Println("After panic")
}
type Test struct {
X int
}
func NullPointer(v *Test) {
fmt.Println(v.X)
}
Đoạn code trên dễ dàng gây ra lỗi panic và stop hàm main
panic: runtime error: invalid memory address or nil pointer dereference
Vậy chúng ta cần làm gì để tránh gây chết hàm main đây
Nếu là java hoặc ngôn ngữ khác thì chúng ta đã có try catch finally
Còn trong golang bạn sẽ có một cách trông đẹp mắt hơn
func main() {
defer func() {
if err := recover(); err != nil {
logrus.Errorln(err)
debug.PrintStack()
}
}()
NullPointer(nil)
time.Sleep(2*time.Second)
fmt.Println("After panic")
}
type Test struct {
X int
}
func NullPointer(v *Test) {
fmt.Println(v.X)
}
Theo cách này thì trong hàm main chúng ta đã thêm một đoạn code để catch lỗi panic null pointer và in ra lỗi và Stacktrace nó luôn
và kết quả như bên dưới
ERRO[0000] runtime error: invalid memory address or nil pointer dereference
goroutine 1 [running]:
runtime/debug.Stack(0x4a80c0, 0xc000060220, 0x0)
/home/bonh/golang/go/src/runtime/debug/stack.go:24 +0x9d
runtime/debug.PrintStack()
/home/bonh/golang/go/src/runtime/debug/stack.go:16 +0x22
main.main.func1()
/home/bonh/Workspace/go/demo/main.go:15 +0x95
panic(0x4c98c0, 0x5a20c0)
/home/bonh/golang/go/src/runtime/panic.go:522 +0x1b5
main.NullPointer(...)
/home/bonh/Workspace/go/demo/main.go:30
main.main()
/home/bonh/Workspace/go/demo/main.go:19 +0x44
Process finished with exit code 0
Bạn để ý thấy dòng cuối cùng là hàm main đã exit code = 0 -> không bị chết hàm main đột ngột
Tuy nhiên nếu chúng ta chạy hàm NullPointer(nil)
với go routine thì chúng ta lại không bắt được panic như đoạn code dưới đây
func main() {
defer func() {
if err := recover(); err != nil {
logrus.Errorln(err)
debug.PrintStack()
}
}()
go NullPointer(nil)
time.Sleep(2*time.Second)
fmt.Println("After panic")
}
type Test struct {
X int
}
func NullPointer(v *Test) {
fmt.Println(v.X)
}
Vì lời gọi hàm defer của chúng ta không thể bắt được panic error trong một routine khác
nếu cố tình code như trên và chạy thì chúng ta nhận đc lỗi sau :
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x4ac3b6]
Bạn để ý thấy hàm main exit code = 2
Vậy nếu như này thì tính sao => đơn giản chỉ cần ném đoạn code chạy routine vào trong 1 hàm khác là chúng ta lại bắt được panic ở hàm main ngay
Đây là đoạn code bắt panic khi dùng go routine
func main() {
defer func() {
if err := recover(); err != nil {
logrus.Errorln(err)
debug.PrintStack()
}
}()
go NullPointer(nil)
time.Sleep(2 * time.Second)
fmt.Println("After panic")
}
type Test struct {
X int
}
func NullPointer(v *Test) {
defer func() {
if err := recover(); err != nil {
logrus.Errorln("inside go routine", err)
debug.PrintStack()
}
}()
fmt.Println(v.X)
}
Vậy túm lại chúng ta cần phải đặt defer để bắt panic trước mỗi hàm được chạy bởi go routine
Comments
Post a Comment