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

1 回复

更多关于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)
}

注意事项

  1. robustly 不能捕获所有类型的 panic,特别是 Go 运行时的一些严重错误(如内存不足)
  2. 在 defer 中再次 panic 可能会导致 robustly 无法捕获
  3. 对于性能敏感的场景,频繁 panic 会影响性能
  4. 不要过度依赖 panic 捕获,良好的错误处理应该是首选

robustly 提供了一种简单有效的方式来增强程序的健壮性,特别是在处理第三方库或不可靠的外部服务时特别有用。

回到顶部