golang实现函数异常捕获与自动恢复的插件库robustly的使用
golang实现函数异常捕获与自动恢复的插件库robustly的使用
robustly简介
Robustly是一个能让代码在出现错误时保持弹性的Go库,它可以从偶发错误中恢复。它还可以让你在应用程序中概率性地注入panic,并在运行时配置这些崩溃点。VividCortex使用它来确保意外问题不会导致代理程序失效。
快速开始
安装robustly:
go get github.com/VividCortex/robustly
在代码中导入并使用:
import (
"github.com/VividCortex/robustly"
)
func main() {
go robustly.Run(func() { somefunc() })
}
func somefunc() {
for {
// 这里放可能panic的代码
}
}
Robustly的目的
Robustly旨在帮助Go程序对在生产环境中才发现的错误更具弹性。它不是通用解决方案,不应过度使用,但在特定条件下非常有价值。
使用Run方法
要使用Run,只需将你想要捕获并重启的代码入口点函数包装起来:
robustly.Run(func() { /* 你的代码 */ }, nil)
要使用Run的可选设置,可以传递一个RunOptions结构体指针:
// RunOptions是保存Run可选参数的结构体
type RunOptions struct {
RateLimit float64 // 每秒崩溃速率限制
Timeout time.Duration // 超时时间(之后Run将停止尝试)
PrintStack bool // 是否打印panic堆栈跟踪
RetryDelay time.Duration // 重试前注入延迟
}
默认选项如下:
robustly.Run(func() { /* 你的代码 */ }, &robustly.RunOptions{
RateLimit: 1.0,
Timeout: time.Second,
PrintStack: false,
RetryDelay: 0 * time.Nanosecond,
})
使用Crash方法
Robustly还包含Crash()
方法,用于在运行时向代码中注入panic。要使用它,在你想要引发崩溃的地方添加以下代码:
robustly.Crash()
使用CrashSetup()
配置崩溃点。传递一个逗号分隔的崩溃点字符串,这些是冒号分隔的file:line:probability
规范。概率应在0到1之间。如果传递特殊规范"VERBOSE"
,它将启用代码中所有崩溃点的打印输出。
例如,如果你在client.go的第53行添加了一个崩溃点,并希望在server.go的第18行也崩溃:
client.go:53:.003,server.go:18:.02
这将在client.go第53行有0.003的概率崩溃,在server.go第18行有0.02的概率崩溃。
完整示例
package main
import (
"fmt"
"time"
"github.com/VividCortex/robustly"
)
func main() {
// 配置崩溃点
robustly.CrashSetup("main.go:20:.1") // 第20行有10%概率崩溃
// 使用Run运行可能崩溃的函数
go robustly.Run(func() {
worker()
}, &robustly.RunOptions{
RateLimit: 5.0, // 每秒最多允许5次崩溃
Timeout: 10 * time.Second, // 10秒后停止尝试
PrintStack: true, // 打印堆栈跟踪
RetryDelay: 100 * time.Millisecond, // 重试前延迟100ms
})
// 防止主程序退出
select {}
}
func worker() {
for i := 0; ; i++ {
fmt.Printf("Working on task %d\n", i)
// 这里可能会崩溃
if i%10 == 0 {
robustly.Crash() // 有10%概率会在这里崩溃
}
time.Sleep(500 * time.Millisecond)
}
}
贡献
我们只接受小修复或改进的拉取请求,包括:
- 小bug修复
- 拼写错误
- 文档或注释
请开issue讨论新功能。新功能的拉取请求将被拒绝。
许可证
本程序© VividCortex 2013,根据MIT许可证授权。
更多关于golang实现函数异常捕获与自动恢复的插件库robustly的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang实现函数异常捕获与自动恢复的插件库robustly的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
使用 robustly 实现 Golang 函数异常捕获与自动恢复
robustly 是一个轻量级的 Golang 库,用于捕获函数执行过程中的 panic 并自动恢复,同时提供错误处理和重试机制。下面我将详细介绍如何使用这个库。
安装 robustly
首先安装 robustly 库:
go get github.com/VividCortex/robustly
基本用法
1. 简单的 panic 捕获
package main
import (
"fmt"
"github.com/VividCortex/robustly"
)
func dangerousFunction() {
fmt.Println("准备执行危险操作")
panic("发生了一个严重的错误!")
}
func main() {
// 使用 robustly 包装函数
err := robustly.Run(dangerousFunction)
if err != nil {
fmt.Printf("捕获到错误: %v\n", err)
}
fmt.Println("程序继续执行")
}
输出结果:
准备执行危险操作
捕获到错误: 发生了一个严重的错误!
程序继续执行
2. 带返回值的函数处理
func divide(a, b int) (int, error) {
if b == 0 {
panic("除数不能为零")
}
return a / b, nil
}
func main() {
result, err := robustly.RunFn(func() (interface{}, error) {
return divide(10, 0)
})
if err != nil {
fmt.Printf("计算失败: %v\n", err)
} else {
fmt.Printf("计算结果: %d\n", result.(int))
}
}
高级功能
1. 重试机制
func unreliableService() error {
// 模拟有时会失败的服务
if rand.Intn(2) == 0 {
return fmt.Errorf("服务暂时不可用")
}
return nil
}
func main() {
// 最多重试3次,每次间隔1秒
retryOpts := &robustly.RetryOptions{
MaxRetries: 3,
Delay: time.Second,
}
err := robustly.RunWithOptions(
func() error { return unreliableService() },
&robustly.Options{Retry: retryOpts},
)
if err != nil {
fmt.Printf("最终失败: %v\n", err)
} else {
fmt.Println("操作成功")
}
}
2. 自定义错误处理
func main() {
opts := &robustly.Options{
OnError: func(err error) {
fmt.Printf("自定义错误处理: %v\n", err)
// 可以在这里添加日志记录、监控上报等逻辑
},
}
err := robustly.RunWithOptions(
func() error {
panic("测试自定义错误处理")
return nil
},
opts,
)
if err != nil {
fmt.Println("主流程知道发生了错误")
}
}
3. 超时控制
func longRunningTask() {
time.Sleep(2 * time.Second)
fmt.Println("任务完成")
}
func main() {
opts := &robustly.Options{
Timeout: time.Second,
}
err := robustly.RunWithOptions(longRunningTask, opts)
if err != nil {
fmt.Printf("任务超时: %v\n", err)
}
}
实际应用示例
HTTP 服务中的使用
package main
import (
"fmt"
"net/http"
"github.com/VividCortex/robustly"
)
func riskyHandler(w http.ResponseWriter, r *http.Request) {
// 可能panic的操作
if r.URL.Path == "/panic" {
panic("故意触发的panic")
}
fmt.Fprintf(w, "请求处理成功: %s", r.URL.Path)
}
func main() {
// 包装处理函数
safeHandler := func(w http.ResponseWriter, r *http.Request) {
err := robustly.Run(func() {
riskyHandler(w, r)
})
if err != nil {
http.Error(w, "服务器内部错误", http.StatusInternalServerError)
fmt.Printf("处理请求时出错: %v\n", err)
}
}
http.HandleFunc("/", safeHandler)
fmt.Println("服务启动在 :8080")
http.ListenAndServe(":8080", nil)
}
注意事项
- robustly 不能捕获所有类型的 panic,特别是 Go 运行时的一些严重错误(如内存不足)
- 在 defer 中再次 panic 可能会导致 robustly 无法捕获
- 对于性能敏感的场景,频繁 panic 会影响性能
- 不要过度依赖 panic 捕获,良好的错误处理应该是首选
robustly 提供了一种简单有效的方式来增强程序的健壮性,特别是在处理第三方库或不可靠的外部服务时特别有用。