Go > Error Handling > Panic and Recover > Best practices with panic
Graceful Panic Recovery in Go
This snippet demonstrates how to use `recover` to handle panics gracefully in Go, preventing program termination and allowing for controlled error handling and cleanup.
Introduction to Panic and Recover
In Go, a `panic` is a runtime error that stops the normal execution flow. It's similar to exceptions in other languages, but Go's approach emphasizes error values instead of exceptions. The `recover` function allows you to regain control after a panic occurs within a `defer` statement. It's crucial for building robust and reliable applications. Proper use of `recover` prevents your program from crashing due to unforeseen errors, enabling you to log the error, perform cleanup operations, or even attempt to retry the operation.
Code Example: Safe Division with Panic Recovery
This example demonstrates a `safeDivide` function that handles potential division by zero errors using `panic` and `recover`. The `defer` statement ensures that the recovery function is always executed, even if a panic occurs. Inside the recovery function, `recover()` retrieves the value passed to `panic()`. If a panic occurred, an error is returned. If no panic occurred, `recover()` returns `nil` and nothing happens. The `log.Println` statement is used to record the panic event. The `main` function calls `safeDivide` with both valid and invalid inputs to showcase the panic recovery mechanism. Even when a division by zero occurs and triggers a panic, the program continues executing, demonstrating the benefit of using `recover`.
package main
import (
"fmt"
"log"
)
func safeDivide(numerator, denominator int) (result int, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("panic occurred: %v", r)
// Log the error
log.Println("Recovered from panic:", r)
}
}()
if denominator == 0 {
panic("division by zero")
}
result = numerator / denominator
return result, nil
}
func main() {
res, err := safeDivide(10, 2)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Result:", res)
}
res, err = safeDivide(10, 0)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Result:", res)
}
fmt.Println("Program continues...")
}
Concepts Behind the Snippet
This snippet illustrates the core concepts of panic and recover in Go:
Real-Life Use Case Section
Consider a web server that handles numerous incoming requests. A panic in one request handler should not bring down the entire server. By using `recover` in the request handling goroutine, you can catch any panics, log the error, and send an appropriate error response to the client, all while keeping the server running and handling other requests. Another use case involves parsing complex data formats. If the parser encounters an unexpected or invalid format, a panic could be triggered. Using `recover` allows the parser to gracefully handle the error and return a more informative error message to the calling function, avoiding program termination.
Best Practices
Interview Tip
Be prepared to explain the difference between errors and panics in Go. Understand when to use each and how `recover` works. Demonstrate your knowledge of best practices for using `panic` and `recover`, emphasizing that it is not a replacement for standard error handling. Also, be ready to discuss the performance implications of using `panic` and `recover` as excessive use could degrade performance.
When to Use Them
Use `panic` for truly exceptional, unrecoverable errors where continuing execution is unsafe. Use `recover` to prevent program termination in critical sections like server request handlers or background worker processes. Avoid using `panic` for expected errors; use error values instead.
Memory Footprint
The memory footprint of `panic` and `recover` is relatively small unless the panic contains large data structures. However, frequent panics and recovers can lead to a performance overhead due to stack unwinding and the execution of deferred functions. Therefore, it's best to avoid excessive use of `panic` and `recover`.
Alternatives
The primary alternative to `panic` and `recover` is to use error values for error handling. This is the preferred approach in Go for most situations. Error values provide more control over error propagation and handling. Libraries like `github.com/pkg/errors` can provide additional context and stack traces for error values, making debugging easier.
Pros
Cons
FAQ
-
When should I use `panic`?
Use `panic` only for truly exceptional situations where the program cannot continue safely, such as unrecoverable errors or data corruption. It should not be used for expected errors, like file not found, or invalid user input, which should be handled with error values. -
Can I use `recover` to handle any error?
No, `recover` only handles panics. It cannot be used to recover from standard errors returned as error values. These require traditional error handling mechanisms. -
What happens if I don't recover from a panic?
If a panic is not recovered, the program will terminate and print a stack trace to standard error.