4 回答
TA贡献1841条经验 获得超3个赞
我进行更简单的重试。
使用更简单的循环逻辑来确保正确性。
我们在执行重试之前会睡觉,因此请用作睡眠的条件。
i > 0
代码如下:
func retry(attempts int, sleep time.Duration, f func() error) (err error) {
for i := 0; i < attempts; i++ {
if i > 0 {
log.Println("retrying after error:", err)
time.Sleep(sleep)
sleep *= 2
}
err = f()
if err == nil {
return nil
}
}
return fmt.Errorf("after %d attempts, last error: %s", attempts, err)
}
TA贡献1816条经验 获得超6个赞
我知道这是一个古老的问题,但在搜索重试时遇到了它,并将其用作解决方案的基础。
此版本可以接受具有 2 个返回值的函数,并在 golang 1.18 中使用泛型来实现这一点。我在1.17中尝试过,但无法找到使该方法通用的方法。
这可以扩展到任何类型的任意数量的返回值。我在这里使用过,但可以限制为类型列表。any
func retry[T any](attempts int, sleep int, f func() (T, error)) (result T, err error) {
for i := 0; i < attempts; i++ {
if i > 0 {
log.Println("retrying after error:", err)
time.Sleep(time.Duration(sleep) * time.Second)
sleep *= 2
}
result, err = f()
if err == nil {
return result, nil
}
}
return result, fmt.Errorf("after %d attempts, last error: %s", attempts, err)
}
用法示例:
var config Configuration
something, err := retry(config.RetryAttempts, config.RetrySleep, func() (Something, error) { return GetSomething(config.Parameter) })
func GetSomething(parameter string) (something Something, err error) {
// Do something flakey here that might need a retry...
return something, error
}
希望这能帮助与我具有相同用例的人。
TA贡献1803条经验 获得超6个赞
您正在调用的函数正在使用上下文。因此,处理该上下文非常重要。
如果您不知道上下文是什么以及如何使用它,我会推荐该帖子:https://blog.golang.org/context
重试函数还应处理上下文。只是为了让你走上正轨,我给你一个简单的实现。
func retryMyServiceFunction(ctx context.Context, place uint, length uint, sleep time.Duration) {
for {
select {
case ctx.Done():
return
default:
err := MyServiceFunction(ctx, place, length)
if err != nil {
log.Println("handle error here!", err)
time.Sleep(sleep)
} else {
return
}
}
}
}
我不喜欢睡眠部分。因此,您应该分析返回的错误。此外,您还必须考虑超时。当您让服务长时间休眠时,可能会有超时。
TA贡献1155条经验 获得超0个赞
在GoPlayground中接受的答案的评论中,我会考虑添加一些东西。在 for 循环中使用 continue 和 break 会使循环更加简单,因为不使用该语句。此外,我会在所有函数中使用早期返回来直接返回错误。最后,我会一直使用错误来检查函数是否失败,检查值的有效性应该在执行的函数本身内部。if i > 0 {
这将是我的小尝试:
package main
import (
"errors"
"fmt"
"log"
"time"
)
func main() {
var complicatedFunctionPassing bool = false
var attempts int = 5
// if complicatedFunctionPassing is true retry just makes one try
// if complicatedFunctionPassing is false retry makes ... attempts
err := retry(attempts, time.Second, func() (err error) {
if !complicatedFunctionPassing {
return errors.New("somthing went wrong in the important function")
}
log.Println("Complicated function passed")
return nil
})
if err != nil {
log.Printf("failed after %d attempts with error: %s", attempts, err.Error())
}
}
func retry(attempts int, sleep time.Duration, f func() error) (err error) {
for i := 0; i < attempts; i++ {
fmt.Println("This is attempt number", i+1)
// calling the important function
err = f()
if err != nil {
log.Printf("error occured after attempt number %d: %s", i+1, err.Error())
log.Println("sleeping for: ", sleep.String())
time.Sleep(sleep)
sleep *= 2
continue
}
break
}
return err
}
你可以在这里尝试一下:https://go.dev/play/p/Ag8ObCb980U
- 4 回答
- 0 关注
- 124 浏览
添加回答
举报