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

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

獲取 singleflight.Group.Do 重試

獲取 singleflight.Group.Do 重試

Go
撒科打諢 2023-02-06 19:39:12
我正在嘗試使用開箱即用的 singleflight 來緩存請求。我想更進一步,隨后對同一密鑰重試失?。ㄥe誤請求)。為此,我正在調用 group.Forget(Key)。但是后續調用似乎只是重用先前的結果而不是重試。type Result struct {    v int    k string}var group singleflight.Group// see https://encore.dev/blog/advanced-go-concurrencyfunc main() {    if true {        for k := 0; k <= 2; k++ {            go doGroup(context.Background(), "sameKey")        }        <-time.Tick(5 * time.Second)        for k := 0; k <= 3; k++ {            go doGroup(context.Background(), "sameKey")        }        <-time.Tick(30 * time.Second)    }}func doGroup(ctx context.Context, key string) (*Result, error) {    log.Println("Inside normal call")    results, err, shared := group.Do(key, func() (interface{}, error) {        r, e := doExpensive(ctx, key)        // Do this; so if it encountered an error;        // subsequent calls will retry        // didnt work        // perhaps because of timing        if e != nil {            group.Forget(key)        }        return r, e    })    fmt.Printf("Call to multiple callers: %v\n", shared)    // does not retry if error occured    if err != nil {        wrapped := fmt.Errorf("error bruh %s: %w", key, err)        fmt.Printf("%s\n", wrapped.Error())        return nil, wrapped    }    fmt.Printf("Results: %v\n", results)    return results.(*Result), err}func doExpensive(ctx context.Context, key string) (*Result, error) {    log.Printf("Inside Expensive function with key %s\n", key)    <-time.Tick(time.Second * 10)    dice := rand.Int31n(10)    if true {        // <-time.Tick(time.Millisecond * time.Duration(dice*100))        return nil, errors.New("operation failed")    }    <-time.Tick(time.Second * time.Duration(dice))    return &Result{        v: int(dice),        k: key,    }, nil}我已經模擬了調用 doGroup 之間的等待,所以第二次調用實際上忘記了密鑰。但是 doExpensive 函數似乎只被調用過一次??梢栽诖颂幷业轿业拇a的復制品https://go.dev/play/p/psGjFTypU6C
查看完整描述

1 回答

?
守候你守候我

TA貢獻1802條經驗 獲得超10個贊

這里的問題是時間和Forget方法行為的結合。正如文檔中所述:


Forget 告訴 singleflight 忘記一把鑰匙。未來為此鍵調用 Do 將調用該函數,而不是等待較早的調用完成。


那里的Future意味著所有對 的調用都group.Do發生在對 的調用之后group.Forget。在您的示例中,對的所有調用都group.Do發生在調用之前group.Forget,并且所有調用都獲得了第一個失敗調用的結果。可能的方法是在 `group.Do 調用之外進行觸發重試。是這樣的:


package main


import (

    "context"

    "errors"

    "log"

    "math/rand"

    "sync/atomic"

    "time"


    "golang.org/x/sync/singleflight"

)


type Result struct {

    v int

    k string

}


var group singleflight.Group


func main() {

    for k := 0; k <= 2; k++ {

        go doGroup(context.Background(), "sameKey")

    }


    <-time.Tick(5 * time.Second)


    for k := 0; k <= 3; k++ {

        go doGroup(context.Background(), "sameKey")

    }


    <-time.Tick(30 * time.Second)

}


func doGroup(ctx context.Context, key string) (*Result, error) {

    log.Println("Inside normal call")


    for {

        results, err, shared := group.Do(key, func() (interface{}, error) {

            return doExpensive(ctx, key)

        })


        if err != nil {

            log.Printf("Normal call error: %s. Will retry \n", err)

            continue

        }


        log.Printf("Normal call results: %v [shared=%v]\n", results, shared)


        return results.(*Result), err

    }

}


var returnedFirstErr atomic.Bool


func doExpensive(ctx context.Context, key string) (r *Result, e error) {

    log.Printf("Inside Expensive function with key %s\n", key)

    defer func() {

        log.Printf("Result of Expensive function: [%v, %s] for %s\n", r, e, key)

    }()

    <-time.Tick(time.Second * 10)


    dice := rand.Int31n(10)


    if !returnedFirstErr.Load() {

        returnedFirstErr.Store(true)

        return nil, errors.New("operation failed")

    }


    return &Result{

        v: int(dice),

        k: key,

    }, nil

}

旁問。您確定 的行為singleflight是您所需要的,也許您應該改用sync.Once?如果singleflight您阻止多個調用同時發生,即仍然會執行稍后完成的調用。如果sync.Once調用在進程的生命周期內恰好完成一次


查看完整回答
反對 回復 2023-02-06
  • 1 回答
  • 0 關注
  • 114 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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