liveBook · Manning

Recover

As explained in Go in Practice, Second Edition

recover is a Go built-in function that retrieves the value associated with a panicking execution and stops the panic from continuing when called from a deferred function.

A panic normally unwinds the current function stack. If it reaches the top without being handled, the program terminates. Call `recover` inside a deferred function to retrieve the panic value and stop that unwinding. This lets you record or handle a failure instead of letting it crash the program. section 4.3.4

Trap a panic

```go package main import ( "errors" "fmt" ) func main() { defer func() { if value := recover(); value != nil { fmt.Printf("Trapped panic: %v (%T)\n", value, value) } }() yikes() } func yikes() { panic(errors.New("Something bad happened.")) } ``` The anonymous function is registered by `defer` and runs when `main` unwinds. Its call to `recover` obtains the value passed to `panic`; printing `%T` also shows its type. section 4.3.4

Put recovery on the stack that might panic. A goroutine has its own function stack: a panic in a request handler cannot unwind into the function that started that goroutine. In a connection handler, a deferred function can log a recovered panic and close the connection. If many tasks need the same protection, a helper can start each task inside a goroutine with its own deferred recovery function. section 4.3.5 section 4.3.5

Listing 4.20 Handling panics on a goroutine
func handle(conn net.Conn) {
     defer func() {                                       #1
            if err := recover(); err != nil {             #1
                    fmt.Printf("Fatal error: %s", err)    #1
            }                                             #1
            conn.Close()                                  #1
     }()                                                  #1
     reader := bufio.NewReader(conn) #1
     data, err := reader.ReadBytes('\n')
     if err != nil {
            fmt.Println("Failed to read from socket.")
     }
     response(data, conn)
}
func response(data []byte, conn net.Conn) {
     conn.Write(data)
     panic(errors.New("Pretend I’m a real error"))       #2
}

The connection-handler listing places `recover` and connection cleanup in the same deferred function, on the goroutine's own stack. section 4.3.5

How Go in Practice, Second Edition covers it

How deep it goes
Works through deferred recovery and extends it to per-goroutine handlers and a reusable task wrapper.
Examples
Uses a panicking function, a TCP connection handler, an HTTP handler, and a goroutine-launching wrapper.
What it assumes
Assumes basic Go functions while explaining deferred closures and why goroutines require recovery on their own stacks.
What you can do after
Build it from scratch: trap a panic with a deferred function and place recovery inside goroutines that need it.
How it connects
Connects `recover` to `panic`, `defer`, closures, goroutines, function stacks, and connection cleanup.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Go in Practice, Second Edition. The section links point to the parts of the book it draws on.