Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is it wrong to treat panic / recover as throw / catch

Tags:

go

Speaking as a new go enthusiast trying to work with the go way of error handling. To be clear - I like exceptions.

I have a server that accepts a connection , processes a set of requests and replies to them. I found that I can do

if err != nil{
      panic(err)
}

in the deep down processing code

and have

defer func() {
        if err := recover(); err != nil {
            log.Printf("%s: %s", err, debug.Stack()) // line 20
        }
    }()

in the client connection code (each connection is in a goroutine). This nicely wraps everything up, forcefully closes the connection (other defers fire) and my server continues to hum along.

But this feels an awful lot like a throw/catch scenario - which golang states it doesn't support. Questions

  • is this stable. ie recovering a panic is an OK thing to do as an ongoing way of life. Its not intended to just slightly defer an immediate shutdown
  • I looked for a discussion on this topic and did not find it anywhere - any pointers?

I feel that the answer is 'yes it works' and can be used inside you own code, but panic should NOT be used by a library intended for wider use. The standard and polite way for a library to behave is by error returns

like image 566
pm100 Avatar asked Jun 05 '14 22:06

pm100


2 Answers

Yes, you can do what you suggest. There are some situations within the standard packages where panic/recover is used for handling errors. The official Go blog states:

For a real-world example of panic and recover, see the json package from the Go standard library. It decodes JSON-encoded data with a set of recursive functions. When malformed JSON is encountered, the parser calls panic to unwind the stack to the top-level function call, which recovers from the panic and returns an appropriate error value (see the 'error' and 'unmarshal' methods of the decodeState type in decode.go).

Some pointers:

  • Use error for your normal use cases. This should be your default.
  • If your code would get clearer and simpler by using a panic/recover (such as with a recursive call stack), then use it for that particular case.
  • Never let a package leak panics. Panics used within a package should be recovered within the package and returned as an error.
  • Recovering from a panic is stable. Don't worry about continuing execution after a recover. You can see such behavior in standard library such as with the net/http package which recovers from panics within handlers to prevent the entire http server to go crash when panicing on a single request.
like image 107
ANisus Avatar answered Nov 21 '22 15:11

ANisus


Generally most methods won't panic, they will return an error instead, and there's a bit of an overhead of using defer.

So yes, it does work, but the "proper" / "go" way is to return an error instead of using panic / recover.

like image 32
OneOfOne Avatar answered Nov 21 '22 15:11

OneOfOne