继续在 Golang 中重试函数

我正在尝试创建一个功能,该功能将按以下方式工作:

  1. 调用服务函数后,它使用 Fetch 函数从服务(以字节数组的形式出现)获取记录,JSON 取消元帅字节数组,填充结构,然后将结构发送到数据库函数以保存到数据库。

  2. 现在,由于这需要是一个连续的作业,因此我添加了两个 if 条件,如果收到的记录长度为 0,则我们使用重试函数重试拉取记录,否则我们只需写入数据库。

我一直在尝试调试重试函数一段时间,但它只是不起作用,并且在第一次重试后基本上停止了(即使我将尝试指定为100)。我能做些什么来确保,它不断重试拉动记录?

代码如下:

// RETRY FUNCTION

func retry(attempts int, sleep time.Duration, f func() error) (err error) {

for i := 0; ; i++ {

    err = f()

    if err == nil {

        return

    }


    if i >= (attempts - 1) {

        break

    }


    time.Sleep(sleep)

    sleep *= 2


    log.Println("retrying after error:", err)

}

return fmt.Errorf("after %d attempts, last error: %s", attempts, err) }



//Save Data function 


type Records struct {

Messages [][]byte

}


func (s *Service) SaveData(records Records, lastSentPlace uint) error {


//lastSentPlace is sent as 0 to begin with.

for i := lastSentPlace; i <= records.Place-1; i++ {


    var msg Records

    msg.Unmarshal(records.Messages[i])


    order := MyStruct{

        Fruit:    msg.Fruit,

        Burger:   msg.Burger,

        Fries:    msg.Fries,

     }


    err := s.db.UpdateOrder(context.TODO(), nil , order)

    if err != nil {

        logging.Error("Error occured...")

    }

    

}return nil}




//Service function (This runs as a batch, which is why we need retrying)


func (s *Service) MyServiceFunction(ctx context.Context, place uint, length uint) (err error) {


var lastSentPlace = place


records, err := s.Poll(context.Background(), place, length)

if err != nil {

    logging.Info(err)

}

我认为,问题在于我尝试实现重试函数的方式,我已经尝试调试了一段时间,但是作为该语言的新手,我真的卡住了。我想做的是,如果没有找到任何记录,就实现回退。任何帮助都非常感谢。


茅侃侃
浏览 125回答 4
4回答

偶然的你

我进行更简单的重试。使用更简单的循环逻辑来确保正确性。我们在执行重试之前会睡觉,因此请用作睡眠的条件。i > 0代码如下:func retry(attempts int, sleep time.Duration, f func() error) (err error) {&nbsp; &nbsp; for i := 0; i < attempts; i++ {&nbsp; &nbsp; &nbsp; &nbsp; if i > 0 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log.Println("retrying after error:", err)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; time.Sleep(sleep)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sleep *= 2&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; err = f()&nbsp; &nbsp; &nbsp; &nbsp; if err == nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nil&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return fmt.Errorf("after %d attempts, last error: %s", attempts, err)}

潇湘沐

我知道这是一个古老的问题,但在搜索重试时遇到了它,并将其用作解决方案的基础。此版本可以接受具有 2 个返回值的函数,并在 golang 1.18 中使用泛型来实现这一点。我在1.17中尝试过,但无法找到使该方法通用的方法。这可以扩展到任何类型的任意数量的返回值。我在这里使用过,但可以限制为类型列表。anyfunc retry[T any](attempts int, sleep int, f func() (T, error)) (result T, err error) {&nbsp; &nbsp; for i := 0; i < attempts; i++ {&nbsp; &nbsp; &nbsp; &nbsp; if i > 0 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log.Println("retrying after error:", err)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; time.Sleep(time.Duration(sleep) * time.Second)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sleep *= 2&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; result, err = f()&nbsp; &nbsp; &nbsp; &nbsp; if err == nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return result, nil&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return result, fmt.Errorf("after %d attempts, last error: %s", attempts, err)}用法示例:var config Configurationsomething, err := retry(config.RetryAttempts, config.RetrySleep, func() (Something, error) { return GetSomething(config.Parameter) })func GetSomething(parameter string) (something Something, err error) {&nbsp; &nbsp; // Do something flakey here that might need a retry...&nbsp; &nbsp; return something, error}希望这能帮助与我具有相同用例的人。

慕码人8056858

您正在调用的函数正在使用上下文。因此,处理该上下文非常重要。如果您不知道上下文是什么以及如何使用它,我会推荐该帖子:https://blog.golang.org/context重试函数还应处理上下文。只是为了让你走上正轨,我给你一个简单的实现。func retryMyServiceFunction(ctx context.Context, place uint, length uint, sleep time.Duration) {&nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; select {&nbsp; &nbsp; &nbsp; &nbsp; case ctx.Done():&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; default:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; err := MyServiceFunction(ctx, place, length)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log.Println("handle error here!", err)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; time.Sleep(sleep)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}我不喜欢睡眠部分。因此,您应该分析返回的错误。此外,您还必须考虑超时。当您让服务长时间休眠时,可能会有超时。

白衣非少年

在GoPlayground中接受的答案的评论中,我会考虑添加一些东西。在 for 循环中使用 continue 和 break 会使循环更加简单,因为不使用该语句。此外,我会在所有函数中使用早期返回来直接返回错误。最后,我会一直使用错误来检查函数是否失败,检查值的有效性应该在执行的函数本身内部。if i > 0 {这将是我的小尝试:package mainimport (&nbsp; &nbsp; "errors"&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "log"&nbsp; &nbsp; "time")func main() {&nbsp; &nbsp; var complicatedFunctionPassing bool = false&nbsp; &nbsp; var attempts int = 5&nbsp; &nbsp; // if complicatedFunctionPassing is true retry just makes one try&nbsp; &nbsp; // if complicatedFunctionPassing is false retry makes ... attempts&nbsp; &nbsp; err := retry(attempts, time.Second, func() (err error) {&nbsp; &nbsp; &nbsp; &nbsp; if !complicatedFunctionPassing {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return errors.New("somthing went wrong in the important function")&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; log.Println("Complicated function passed")&nbsp; &nbsp; &nbsp; &nbsp; return nil&nbsp; &nbsp; })&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; log.Printf("failed after %d attempts with error: %s", attempts, err.Error())&nbsp; &nbsp; }}func retry(attempts int, sleep time.Duration, f func() error) (err error) {&nbsp; &nbsp; for i := 0; i < attempts; i++ {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("This is attempt number", i+1)&nbsp; &nbsp; &nbsp; &nbsp; // calling the important function&nbsp; &nbsp; &nbsp; &nbsp; err = f()&nbsp; &nbsp; &nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log.Printf("error occured after attempt number %d: %s", i+1, err.Error())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log.Println("sleeping for: ", sleep.String())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; time.Sleep(sleep)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sleep *= 2&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; break&nbsp; &nbsp; }&nbsp; &nbsp; return err}你可以在这里尝试一下:https://go.dev/play/p/Ag8ObCb980U
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go