recover

👉 recover — cơ chế “chống cháy” khi panic.


🔥 1. recover là gì?

recover()builtin function của Go dùng để phục hồi lại chương trình từ panic.

Nhưng chỉ hoạt động bên trong một defer function.

defer func() {
    if r := recover(); r != nil {
        fmt.Println("Recovered from panic:", r)
    }
}()

⚙️ 2. Cách hoạt động

Khi một panic xảy ra:

  1. Go bắt đầu unwind call stack.

  2. Mọi defer được thực thi theo thứ tự LIFO.

  3. Nếu trong bất kỳ defer nào gọi recover() — thì panic sẽ dừng lại, chương trình tiếp tục chạy bình thường.


✅ 3. Ví dụ đơn giản

func safeDivide(a, b int) {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered:", r)
        }
    }()
    fmt.Println(a / b) // panic nếu b = 0
}

func main() {
    safeDivide(10, 0)
    fmt.Println("Program continues...")
}

Output:

Recovered: runtime error: integer divide by zero
Program continues...

🔄 4. Kết hợp panic + recover + defer

func mustInit() {
    defer func() {
        if err := recover(); err != nil {
            log.Println("Init failed:", err)
        }
    }()
    panic("DB not found")
}

Đây là cách "safe startup" thường dùng trong app backend.


🧱 5. Use case phổ biến của recover

✅ a. Middleware HTTP — chống crash toàn server

func RecoveryMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        defer func() {
            if err := recover(); err != nil {
                log.Printf("Recovered: %v", err)
                http.Error(w, "Internal Server Error", http.StatusInternalServerError)
            }
        }()
        next.ServeHTTP(w, r)
    })
}

Dùng để đảm bảo nếu có panic trong bất kỳ handler nào, server không crash.


✅ b. Job runner / worker pool

func worker(job func()) {
    defer func() {
        if err := recover(); err != nil {
            log.Println("Recovered job panic:", err)
        }
    }()
    job()
}

Bảo vệ worker khi xử lý task bất ổn.


❌ 6. Cảnh báo quan trọng

Sai lầm
Giải thích

Recover bên ngoài defer

Không hoạt động

Lạm dụng recover để ẩn lỗi

Làm mất trace gây khó debug

Không log lỗi

Bạn recover rồi “nuốt luôn lỗi” => khó trace production bug


✅ Best Practices của recover

Tình huống
Khuyến nghị

Protect HTTP server

Viết middleware có defer+recover

Protect goroutines

Bọc goroutine bằng wrapper recover

Logging error

Luôn log rõ panic + stack trace

Không dùng trong business logic

Không recover rồi tiếp tục xử lý logic sai


🧠 Bonus: Ghi lại stack trace khi recover

defer func() {
    if r := recover(); r != nil {
        log.Printf("panic: %v\n%s", r, debug.Stack())
    }
}()

Thêm runtime/debug để in call stack giúp debug sâu.


🔚 Tổng kết

Cơ chế
Mục đích

panic

Ném lỗi nghiêm trọng

defer

Đảm bảo cleanup chạy cuối

recover

Cứu chương trình khỏi crash


Last updated