From c740d02821a9ad7b081723bf260bf74c16570698 Mon Sep 17 00:00:00 2001 From: Kylesoda <249518290+kylesoda@users.noreply.github.com> Date: Mon, 13 Apr 2026 22:26:53 -0500 Subject: [PATCH] feat: add backoff package for retry logic and implement example usage in new backoff-test script --- go.mod | 2 ++ go.sum | 4 +++ scripts/backoff-test/main.go | 58 ++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 scripts/backoff-test/main.go diff --git a/go.mod b/go.mod index 96170be..04d49fa 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,8 @@ require ( ) require ( + github.com/cenkalti/backoff v2.2.1+incompatible // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect diff --git a/go.sum b/go.sum index 7fecac7..8508679 100644 --- a/go.sum +++ b/go.sum @@ -16,6 +16,10 @@ github.com/alecthomas/assert/v2 v2.10.0 h1:jjRCHsj6hBJhkmhznrCzoNpbA3zqy0fYiUcYZ github.com/alecthomas/assert/v2 v2.10.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= +github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= diff --git a/scripts/backoff-test/main.go b/scripts/backoff-test/main.go new file mode 100644 index 0000000..a454924 --- /dev/null +++ b/scripts/backoff-test/main.go @@ -0,0 +1,58 @@ +package main + +import ( + "context" + "errors" + "fmt" + "net/http" + "strconv" + + "github.com/cenkalti/backoff/v5" +) + +func ExampleRetry() { + // Define an operation function that returns a value and an error. + // The value can be any type. + // We'll pass this operation to Retry function. + operation := func() (string, error) { + // An example request that may fail. + resp, err := http.Get("http://httpbin.org/get") + if err != nil { + return "", err + } + defer resp.Body.Close() + + // If we are being rate limited, return a RetryAfter to specify how long to wait. + // This will also reset the backoff policy. + if resp.StatusCode == 429 { + seconds, err := strconv.ParseInt(resp.Header.Get("Retry-After"), 10, 64) + if err == nil { + return "", backoff.RetryAfter(int(seconds)) + } + } + + // In case of non-retriable error, return Permanent error to stop retrying. + // For this HTTP example, client errors are non-retriable. + if resp.StatusCode >= 400 && resp.StatusCode < 500 { + return "", backoff.Permanent(errors.New("bad request")) + } + + // Return successful response. + return "hello", nil + } + + result, err := backoff.Retry(context.TODO(), operation, backoff.WithBackOff(backoff.NewExponentialBackOff())) + if err != nil { + fmt.Println("Error:", err) + return + } + + // Operation is successful after retries. + + fmt.Println(result) + // Output: hello +} + +func main() { + ExampleRetry() +}