SoFunction
Updated on 2025-03-05

Some pitfalls in the use of golang recover function

text

It is well known that the recover function in golang can catch panic to prevent the entire service from being unavailable in the event of an exception. However, in some cases, recover cannot catch panic. Here are some of these situations.

1. Under normal circumstances

package main
import "fmt"
func main(){
    defer func(){
        if err := recover();err != nil{
            ("err = %v",err)
        }
    }()
    panic("a panic")
}
Print results:
err = a panic
Process finished with exit code 0

Can catch panic normally

2. Goroutine panic

Previously, the online environment had panic interfaces, which made the service unavailable, so my colleague directly added a recovery to the main function and thought that everything was worry-free. In fact, recover cannot catch panics in coroutines.

package main
import "fmt"
func main(){
    defer func(){
        if err := recover();err != nil{
            ("err = %v",err)
        }
    }()
    go func(){
        panic("a panic")
    }()
    select{}
}
Print results:
panic: a panic
goroutine 6 [running]:
.func2()
    I:/goProject/:13 +0x40
created by 
    I:/goProject/:12 +0x5e

In fact, panic will still cause the service to be unavailable.

Correct writing

package main
import "fmt"
func main(){
    go func(){
        defer func(){
            if err := recover();err != nil{
                ("err = %v",err)
            }
        }()
        panic("a panic")
    }()
    select {}
}
Return value:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [select (no cases)]:
()
    I:/goProject/:15 +0x41
err = a panic
Process finished with exit code 2

You can see that the panic is caught normally, and because the select statement is blocked, a deadlock error was reported.

3. Indirect call recovery

When I wanted to encapsulate the recover into a function, I found that the recover did not take effect, because the recover will only take effect when it is called directly by the defer statement. Panic cannot be captured correctly when recover is inside other functions.

package main
import "fmt"
func main(){
    defer cover()
    panic("a panic")
}
func cover(){
    defer func(){
        if err := recover();err!= nil{
            (err)
        }
    }()
}
Return value:
panic: a panic
goroutine 1 [running]:
()
    I:/goProject/:7 +0x62

4. nil panic

To be captured, a condition needs to be met, that is, panic is not nil panic, otherwise it is impossible to know whether panic has not occurred or panic itself is nil when making capture judgments.

For example, the following code

package main
import "fmt"
func main() {
    defer func(){
        if err := recover();err != nil{
            (err)
        }
        ("after recover")
    }()
    panic(nil)
    select{}
}
Return value:
after recover

Recover does not handle the exception correctly because the value of the exception is nil.

Five, summary

This article tells the story of three types of recovery failure.

  • Panic appears in Ctrip
  • Defer does not call recover directly
  • The value of panic is nil

When writing code, you need to pay attention to avoid the service being unavailable due to these situations. The above are some pitfalls that golang novices often encounter.

The above is the detailed content of some pitfalls in the use of golang recover function. For more information about golang recover function pitfalls, please pay attention to my other related articles!