MST

星途 面试题库

面试题:Go语言中recover在大规模系统错误处理场景的应用

在一个大规模Go语言构建的微服务系统中,某个服务可能会因为各种原因发生panic,例如数据库连接突然中断。请描述如何合理使用recover来捕获panic,并保证服务能继续运行且记录相关错误信息到日志文件中。同时给出关键代码示例。
39.8万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
  1. 使用recover捕获panic的原理
    • 在Go语言中,recover函数只能在defer函数中使用,用于捕获panic并恢复程序的正常执行流。当panic发生时,函数的执行会立即停止,函数中的defer语句会按照后进先出的顺序执行,如果在defer函数中调用recover,就可以捕获到panic的值,从而避免程序崩溃。
  2. 将错误信息记录到日志文件
    • 可以使用Go标准库中的log包来记录日志。在捕获到panic后,将相关信息(如panic的值、时间等)写入日志文件。
  3. 关键代码示例
package main

import (
    "log"
    "os"
)

func main() {
    defer func() {
        if r := recover(); r!= nil {
            // 打开日志文件,这里假设日志文件名为panic.log
            file, err := os.OpenFile("panic.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
            if err!= nil {
                log.Println("Failed to open log file:", err)
                return
            }
            defer file.Close()
            logger := log.New(file, "", log.LstdFlags)
            logger.Printf("Panic occurred: %v\n", r)
        }
    }()

    // 模拟可能发生panic的操作,例如数据库连接中断
    panic("Database connection lost")
}

在实际的微服务场景中,main函数中的业务逻辑可能是具体的服务处理函数,比如处理HTTP请求的函数。例如:

package main

import (
    "log"
    "net/http"
)

func handleRequest(w http.ResponseWriter, r *http.Request) {
    defer func() {
        if r := recover(); r!= nil {
            // 打开日志文件,这里假设日志文件名为panic.log
            file, err := os.OpenFile("panic.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
            if err!= nil {
                log.Println("Failed to open log file:", err)
                return
            }
            defer file.Close()
            logger := log.New(file, "", log.LstdFlags)
            logger.Printf("Panic occurred in request handling: %v\n", r)
            http.Error(w, "Internal Server Error", http.StatusInternalServerError)
        }
    }()

    // 模拟可能发生panic的数据库操作
    // 这里假设是一个数据库查询操作
    // 实际中可能是使用数据库连接池进行查询
    // 例如:
    // rows, err := db.Query("SELECT * FROM some_table")
    // if err!= nil {
    //     panic("Database query error: " + err.Error())
    // }
    // 这里简单模拟一个panic
    panic("Database query error")
}

func main() {
    http.HandleFunc("/", handleRequest)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

通过以上方式,在大规模Go语言微服务系统中,当某个服务发生panic时,可以捕获panic,记录相关错误信息到日志文件,并保证服务能继续运行(对于HTTP服务,能继续处理后续请求,只是对发生panic的请求返回错误响应)。