亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

繼續在 Golang 中重試函數

繼續在 Golang 中重試函數

Go
茅侃侃 2022-08-24 16:18:34
我正在嘗試創建一個功能,該功能將按以下方式工作:調用服務函數后,它使用 Fetch 函數從服務(以字節數組的形式出現)獲取記錄,JSON 取消元帥字節數組,填充結構,然后將結構發送到數據庫函數以保存到數據庫。現在,由于這需要是一個連續的作業,因此我添加了兩個 if 條件,如果收到的記錄長度為 0,則我們使用重試函數重試拉取記錄,否則我們只需寫入數據庫。我一直在嘗試調試重試函數一段時間,但它只是不起作用,并且在第一次重試后基本上停止了(即使我將嘗試指定為100)。我能做些什么來確保,它不斷重試拉動記錄?代碼如下:// RETRY FUNCTIONfunc 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 = placerecords, err := s.Poll(context.Background(), place, length)if err != nil {    logging.Info(err)}我認為,問題在于我嘗試實現重試函數的方式,我已經嘗試調試了一段時間,但是作為該語言的新手,我真的卡住了。我想做的是,如果沒有找到任何記錄,就實現回退。任何幫助都非常感謝。
查看完整描述

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)

}


查看完整回答
反對 回復 2022-08-24
?
瀟湘沐

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

}

希望這能幫助與我具有相同用例的人。


查看完整回答
反對 回復 2022-08-24
?
慕碼人8056858

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

            }

        }

    }

}

我不喜歡睡眠部分。因此,您應該分析返回的錯誤。此外,您還必須考慮超時。當您讓服務長時間休眠時,可能會有超時。


查看完整回答
反對 回復 2022-08-24
?
白衣非少年

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


查看完整回答
反對 回復 2022-08-24
  • 4 回答
  • 0 關注
  • 170 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號