-
Notifications
You must be signed in to change notification settings - Fork 5
feature: adopt retry-go for HTTP retry logic #51
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,20 @@ | ||
| github.com/avast/retry-go/v4 v4.7.0 h1:yjDs35SlGvKwRNSykujfjdMxMhMQQM0TnIjJaHB+Zio= | ||
| github.com/avast/retry-go/v4 v4.7.0/go.mod h1:ZMPDa3sY2bKgpLtap9JRUgk2yTAba7cgiFhqxY2Sg6Q= | ||
| github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
| github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
| github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= | ||
| github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= | ||
| github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
| github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= | ||
| github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= | ||
| github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= | ||
| github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= | ||
| go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= | ||
| go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= | ||
| go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE= | ||
| go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI= | ||
| gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
| gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||
| sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= | ||
| sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,6 +25,8 @@ import ( | |
| "sort" | ||
| "strings" | ||
| "time" | ||
|
|
||
| "github.com/avast/retry-go/v4" | ||
| ) | ||
|
|
||
| // PackagesNotFoundError is returned when requested package names are not found in the catalog. | ||
|
|
@@ -105,28 +107,23 @@ func Fetch() (*Catalog, error) { | |
| return FetchFrom(APIURL, &http.Client{Timeout: 30 * time.Second}) | ||
| } | ||
|
|
||
| var sleepFunc = time.Sleep | ||
| var retryOptions = []retry.Option{ | ||
| retry.Attempts(3), | ||
| retry.Delay(60 * time.Second), | ||
| retry.DelayType(retry.BackOffDelay), | ||
| retry.LastErrorOnly(true), | ||
| } | ||
|
|
||
| // FetchFrom retrieves the product catalog from the given URL using the provided HTTP client. | ||
| // It retries up to 3 times with exponential backoff on errors. | ||
| // It makes up to 3 attempts with exponential backoff on errors. | ||
| func FetchFrom(url string, client *http.Client) (*Catalog, error) { | ||
| const maxRetries = 3 | ||
| var lastErr error | ||
|
|
||
| for attempt := range maxRetries { | ||
| if attempt > 0 { | ||
| // attempt 1: 60s, attempt 2: 120s | ||
| sleepFunc(time.Duration(60<<(attempt-1)) * time.Second) | ||
| } | ||
|
|
||
| catalog, err := fetch(url, client) | ||
| if err == nil { | ||
| return catalog, nil | ||
| } | ||
| lastErr = err | ||
| catalog, err := retry.DoWithData(func() (*Catalog, error) { | ||
| return fetch(url, client) | ||
| }, retryOptions...) | ||
| if err != nil { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [low] error-message-informativeness The error message changed from 'after 3 attempts: ...' to 'after retries: ...', losing the attempt count and introducing a terminology inconsistency with the comment on line 117 ('makes up to 3 attempts'). Since the count is a compile-time constant (retry.Attempts(3)), the information loss is minor but including it is a cheap improvement. Suggested fix: Change to fmt.Errorf("after 3 attempts: %%w", err) to restore the count and align with the comment's terminology. |
||
| return nil, fmt.Errorf("after retries: %w", err) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [low] error-message-change The error message changed from 'after 3 attempts: ' to 'after retries: ', losing the attempt count from the diagnostic message. No downstream code or test depends on this exact text, and the underlying error is still properly wrapped via %w, so errors.Is/errors.As continue to work. This is a minor loss of information in error diagnostics that could be useful when debugging production failures. Suggested fix: Consider preserving the attempt count, e.g. fmt.Errorf("after 3 attempts: %w", err). |
||
| } | ||
|
|
||
| return nil, fmt.Errorf("after %d attempts: %w", maxRetries, lastErr) | ||
| return catalog, nil | ||
| } | ||
|
|
||
| func fetch(url string, client *http.Client) (*Catalog, error) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[low] architecture-coherence
New dependency github.com/avast/retry-go/v4 is not reflected in CLAUDE.md's Tech Stack section, which currently lists only sigs.k8s.io/yaml and spf13/pflag.
Suggested fix: Update CLAUDE.md Tech Stack section to include avast/retry-go/v4 for HTTP retry logic.