Golang中retry.Do的额外功能实现

Golang中retry.Do的额外功能实现 我想使用 retry.Do,但希望它能提供更多功能。例如,每次重试的错误只能在 Do 成功或达到最大重试次数失败后,作为一个切片一起获取。

其次,配置参数(MaxJitterDelayTypeMaxRetries)是在调用 Do 时配置的,之后它们保持静态。我希望有一个功能,能够启动一个 retry.Do 调用,然后根据其状态实时修改这些参数。

是否有另一个包提供这种额外的、细粒度的功能?关于您对 retry.Do 的使用,您是否希望它提供任何额外的功能?

4 回复

你能指定这是哪个包吗?

更多关于Golang中retry.Do的额外功能实现的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我猜这个就是那个包。

在阅读源代码后(假设我们讨论的是同一个包),我认为你可以实现自己的 DelayTypeFunc,并将其委托给其他延迟函数:

type ChangeableDelayType struct {
    Func retry.DelayTypeFunc
}

func (c *ChangeableDelayType) DelayType(n uint, err error, config *Config) time.Duration {
    return c.Func(n, err, config)
}

// ...

c := &ChangeableDelayType{
    Func: retry.BackOfDelay,
}

retry.Do(
    /* ... */,
    retry.DelayType(c.DelayType),
)

// 现在你可以通过修改 c.Func 来改变行为,但要注意
// 对 c.Func 的并发访问:可能需要添加互斥锁来
// 同步访问。

对于需要更细粒度控制的场景,你可以考虑使用 github.com/avast/retry-go 包的 Retry 函数配合自定义配置。以下是实现你所需功能的示例:

package main

import (
    "errors"
    "fmt"
    "time"

    "github.com/avast/retry-go"
)

func main() {
    var allErrors []error
    
    // 自定义错误收集器
    errorCollector := func(err error) {
        allErrors = append(allErrors, err)
    }

    // 动态配置
    config := &retryConfig{
        maxRetries: 3,
        maxDelay:   2 * time.Second,
    }

    err := retry.Do(
        func() error {
            // 你的业务逻辑
            return errors.New("模拟失败")
        },
        retry.Attempts(uint(config.maxRetries)),
        retry.MaxDelay(config.maxDelay),
        retry.OnRetry(func(n uint, err error) {
            errorCollector(err)
            // 动态调整参数
            if n == 1 {
                config.maxRetries = 5
            }
        }),
    )

    // 收集最终错误
    if err != nil {
        errorCollector(err)
    }

    fmt.Printf("所有错误: %v\n", allErrors)
    fmt.Printf("最终错误: %v\n", err)
}

// 自定义配置结构
type retryConfig struct {
    maxRetries int
    maxDelay   time.Duration
}

对于需要实时修改参数的需求,可以结合上下文(context)实现:

package main

import (
    "context"
    "errors"
    "fmt"
    "time"

    "github.com/avast/retry-go"
)

func main() {
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    dynamicConfig := &DynamicRetryConfig{
        MaxRetries: 3,
        MaxDelay:   1 * time.Second,
    }

    // 监控goroutine动态更新配置
    go monitorAndUpdateConfig(ctx, dynamicConfig)

    var errors []error
    err := retry.Do(
        func() error {
            return operation()
        },
        retry.Attempts(uint(dynamicConfig.MaxRetries)),
        retry.MaxDelay(dynamicConfig.MaxDelay),
        retry.OnRetry(func(n uint, err error) {
            errors = append(errors, err)
            fmt.Printf("重试 %d, 当前配置: %+v\n", n, dynamicConfig)
        }),
        retry.Context(ctx),
    )

    if err != nil {
        errors = append(errors, err)
    }

    fmt.Printf("收集到的错误: %v\n", errors)
}

func operation() error {
    return errors.New("操作失败")
}

type DynamicRetryConfig struct {
    MaxRetries int
    MaxDelay   time.Duration
}

func monitorAndUpdateConfig(ctx context.Context, config *DynamicRetryConfig) {
    ticker := time.NewTicker(500 * time.Millisecond)
    defer ticker.Stop()

    for {
        select {
        case <-ctx.Done():
            return
        case <-ticker.C:
            // 根据条件动态更新配置
            config.MaxDelay = 2 * time.Second
        }
    }
}

如果需要更高级的控制,可以考虑 github.com/cenkalti/backoff 包:

package main

import (
    "errors"
    "fmt"
    "time"

    "github.com/cenkalti/backoff"
)

func main() {
    var allErrors []error
    
    b := backoff.NewExponentialBackOff()
    b.MaxElapsedTime = 30 * time.Second
    
    operation := func() error {
        err := someOperation()
        if err != nil {
            allErrors = append(allErrors, err)
        }
        return err
    }

    err := backoff.Retry(operation, b)
    
    if err != nil {
        allErrors = append(allErrors, err)
    }
    
    fmt.Printf("所有错误记录: %v\n", allErrors)
}

func someOperation() error {
    return errors.New("操作失败")
}

这些方案提供了错误收集和动态配置调整的能力。retry-goOnRetry 回调可以收集每次重试的错误,而通过上下文或外部监控可以实现在重试过程中动态调整参数。

回到顶部