介绍
gretry是一个golang的通用重试工具, 它可以用于任何需要重试的场景, 比如网络请求, 数据库操作等, 只要出现了错误你想进行重试, 就可以使用gretry.
如何使用
通常做法
package main
import (
"fmt"
"gitee.com/kaylee595/gretry"
"net/http"
)
func main() {
req, err := http.NewRequest(http.MethodGet, "https://example.com", nil)
if err != nil {
panic(err)
}
resp, err := gretry.Do[*http.Response](func() (any, error) {
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
if resp.StatusCode >= http.StatusBadRequest {
_ = resp.Body.Close()
return nil, fmt.Errorf("status code is %d", resp.StatusCode)
}
return resp, nil
})
if err != nil {
panic(err)
}
fmt.Println(resp.StatusCode)
}
某些错误不进行重试
package main
import (
"context"
"errors"
"fmt"
"gitee.com/kaylee595/gretry"
"net/http"
"time"
)
func main() {
timeoutCtx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
defer cancel()
req, err := http.NewRequestWithContext(timeoutCtx, http.MethodGet, "https://example.com", nil)
if err != nil {
panic(err)
}
resp, err := gretry.Do[*http.Response](func() (any, error) {
resp, err := http.DefaultClient.Do(req)
if err != nil {
if errors.Is(err, context.Canceled) {
// 第二个值返回nil, 重试器不会进行重试.
return err, nil
}
return nil, err
}
if resp.StatusCode >= http.StatusBadRequest {
_ = resp.Body.Close()
return nil, fmt.Errorf("status code is %d", resp.StatusCode)
}
return resp, nil
})
if err != nil {
panic(err)
}
fmt.Println(resp.StatusCode)
}
不使用默认retry参数
默认retry实例参数请参考gretry.New()
注释.
package main
import (
"context"
"errors"
"fmt"
"gitee.com/kaylee595/gretry"
"net/http"
"time"
)
func main() {
// 最大重试10次
r := gretry.New(10)
// 使用均匀抖动线性退避, 具体参考它们的注释.
r.SetDelayCalculator(
DelayCalculatorWithEqualJitter(
DelayCalculatorLinear(200*time.Millisecond, 2*time.Second),
),
)
// 创建请求
timeoutCtx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
defer cancel()
req, err := http.NewRequestWithContext(timeoutCtx, http.MethodGet, "https://example.com", nil)
if err != nil {
panic(err)
}
// 发送请求. AssertType可以帮助断言返回的第一个值的类型.
resp, err := AssertType[*http.Response{}](r.Do(func() (any, error) {
resp, err := http.DefaultClient.Do(req)
if err != nil {
if errors.Is(err, context.Canceled) {
// 第二个值返回nil, 重试器不会进行重试.
return err, nil
}
return nil, err
}
if resp.StatusCode >= http.StatusBadRequest {
_ = resp.Body.Close()
}
return resp, nil
}))
if err != nil {
panic(err)
}
fmt.Println(resp.StatusCode)
}
用于HTTP请求重试的场景
前面介绍的HTTP请求重试方法, 我已经准备好了开箱即用的RetryTransport.
当错误发生时, 就会自动重试到成功再返回给http.Client.
package main
import (
"fmt"
"gitee.com/kaylee595/gretry/retryTransport"
"github.com/stretchr/testify/require"
"net/http"
)
func main() {
client := &http.Client{
// retryTransport.New参数具体查看该函数的注释
Transport: retryTransport.New(http.DefaultTransport, 3),
}
req, err := http.NewRequest(http.MethodGet, "https://example.com", nil)
if err != nil {
panic(err)
}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
fmt.Println(resp.StatusCode)
}
源码地址: gitee
食用方法: go get gitee.com/kaylee595/gretry