围绕 go-retry RetryFunc 创建一个包装器以接受任何 API 定义

问题描述 投票:0回答:1

我正在使用 https://pkg.go.dev/github.com/sethvargo/go-retry 包从我的应用程序在 GitHub API 服务器上进行重试。该包是其中最简单的一个,有助于重试 Web API 调用。

困扰我的问题是

https://pkg.go.dev/github.com/sethvargo/go-retry#RetryFunc
中的 RetryFunc 采用了表单的闭包

type RetryFunc func(ctx context.Context) error

我有很多 GitHub API 围绕着这个重试逻辑,具有不同数量的参数。

下面的示例代码

func retryDecision(resp *github.Response) error {
    if resp.StatusCode == 0 || (resp.StatusCode >= 500 && resp.StatusCode != http.StatusNotImplemented) {
        return retry.RetryableError(fmt.Errorf("unexpected HTTP status %s", resp.Status))
    }
    return nil
}

func retryWithExpBackoff(ctx context.Context, f func(ctx context.Context) error) error {
    b := retry.NewExponential(1 * time.Second)
    b = retry.WithMaxRetries(5, b)
    b = retry.WithMaxDuration(5*time.Second, b)
    return retry.Do(ctx, b, f)
}

func NewGitHubClient(ctx context.Context, token, repo string) (*github.Client, error) {
    r := strings.Split(repo, "/")
    client := github.NewClient(nil).WithAuthToken(token)

    if err := retryWithExpBackoff(ctx, func(ctx context.Context) error {
        _, resp, err := client.Repositories.Get(ctx, r[0], r[1])
        if retryErr := retryDecision(resp); retryErr != nil {
            return retryErr
        }
        return err
    }); err != nil {
        return nil, err
    }

    return client, nil
}

对于我正在重试实现的每个 API,我最终会进行如下所示的嵌套调用,即这部分代码在我计划实现的每个 API 中重复

    if err := retryWithExpBackoff(ctx, func(ctx context.Context) error {
        // <-------- API that needs to run by retry --------->
        //_, resp, err := client.Repositories.Get(ctx, r[0], r[1])
        if retryErr := retryDecision(resp); retryErr != nil {
            return retryErr
        }
        return err
    }); err != nil {
        return nil, err
    }

我如何重写这个,使

retryWithExpBackoff
采用我计划实现的任何API,但采用重试机制?

代码中引用的GitHub API来自https://pkg.go.dev/github.com/google/go-github/v61/github

go github-api
1个回答
0
投票

我设法找到一种方法以这种方式重写重试逻辑。但仍然会欣赏其他方式。

type GitHubAPIRequest func(ctx context.Context) (*github.Response, error)

func retryWithExpBackoff(ctx context.Context, request GitHubAPIRequest) error {
    b := retry.NewExponential(1 * time.Second)
    b = retry.WithMaxRetries(5, b)
    b = retry.WithMaxDuration(5*time.Second, b)
    return retry.Do(ctx, b, func(ctx context.Context) error {
        response, err := request(ctx)
        if retryErr := retryDecision(response); retryErr != nil {
            return retryErr
        }
        return err
    })
}

func NewGitHubClient(ctx context.Context, token, repo string) (*github.Client, error) {
    r := strings.Split(repo, "/")
    client := github.NewClient(nil).WithAuthToken(token)

    request := func(ctx context.Context) (*github.Response, error) {
        _, resp, err := client.Repositories.Get(ctx, r[0], r[1])
        return resp, err
    }

    if err := retryWithExpBackoff(ctx, request); err != nil {
        return nil, err
    }

    return client, nil
}

虽然这有效,但它将我的 API 限制为

GitHubAPIRequest
的签名,如果我需要访问 GitHub API 的响应而不仅仅是错误,我可能需要稍微调整一下。

© www.soinside.com 2019 - 2024. All rights reserved.