diff --git a/go.mod b/go.mod index be05a14dc..42e3c3de8 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( contrib.go.opencensus.io/exporter/prometheus v0.4.2 contrib.go.opencensus.io/exporter/stackdriver v0.13.14 github.com/acobaugh/osrelease v0.1.0 - github.com/avast/retry-go v3.0.0+incompatible + github.com/avast/retry-go/v4 v4.5.0 github.com/coreos/go-systemd/v22 v22.5.0 github.com/euank/go-kmsg-parser v2.0.0+incompatible github.com/hpcloud/tail v1.0.0 diff --git a/go.sum b/go.sum index 90d663e29..834e1b499 100644 --- a/go.sum +++ b/go.sum @@ -140,8 +140,8 @@ github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgI github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= -github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= +github.com/avast/retry-go/v4 v4.5.0 h1:QoRAZZ90cj5oni2Lsgl2GW8mNTnUCnmpx/iKpwVisHg= +github.com/avast/retry-go/v4 v4.5.0/go.mod h1:7hLEXp0oku2Nir2xBAsg0PTphp9z71bN5Aq1fboC3+I= github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/aws/aws-sdk-go v1.43.11/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= diff --git a/pkg/exporters/stackdriver/stackdriver_exporter.go b/pkg/exporters/stackdriver/stackdriver_exporter.go index 71f8dca76..e65180d68 100644 --- a/pkg/exporters/stackdriver/stackdriver_exporter.go +++ b/pkg/exporters/stackdriver/stackdriver_exporter.go @@ -30,7 +30,7 @@ import ( "google.golang.org/api/option" "k8s.io/klog/v2" - "github.com/avast/retry-go" + "github.com/avast/retry-go/v4" "k8s.io/node-problem-detector/pkg/exporters" seconfig "k8s.io/node-problem-detector/pkg/exporters/stackdriver/config" "k8s.io/node-problem-detector/pkg/types" diff --git a/test/e2e/lib/npd/npd.go b/test/e2e/lib/npd/npd.go index aadf7d97b..40c236c56 100644 --- a/test/e2e/lib/npd/npd.go +++ b/test/e2e/lib/npd/npd.go @@ -26,7 +26,7 @@ import ( "k8s.io/node-problem-detector/pkg/util/metrics" "k8s.io/node-problem-detector/test/e2e/lib/gce" - "github.com/avast/retry-go" + "github.com/avast/retry-go/v4" ) // SetupNPD installs NPD from the test tarball onto the provided GCE instance. diff --git a/test/go.mod b/test/go.mod index ec90f2c7f..58a08ea02 100644 --- a/test/go.mod +++ b/test/go.mod @@ -5,7 +5,7 @@ go 1.20 replace k8s.io/node-problem-detector => ../. require ( - github.com/avast/retry-go v3.0.0+incompatible + github.com/avast/retry-go/v4 v4.5.0 github.com/onsi/ginkgo v1.16.5 github.com/onsi/gomega v1.27.10 github.com/pborman/uuid v1.2.1 diff --git a/test/go.sum b/test/go.sum index d8dc57d93..beda09af7 100644 --- a/test/go.sum +++ b/test/go.sum @@ -106,8 +106,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= -github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= -github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= +github.com/avast/retry-go/v4 v4.5.0 h1:QoRAZZ90cj5oni2Lsgl2GW8mNTnUCnmpx/iKpwVisHg= +github.com/avast/retry-go/v4 v4.5.0/go.mod h1:7hLEXp0oku2Nir2xBAsg0PTphp9z71bN5Aq1fboC3+I= github.com/aws/aws-k8s-tester v1.0.0/go.mod h1:NUNd9k43+h9O5tvwL+4N1Ctb//SapmeeFX1G0/2/0Qc= github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= diff --git a/vendor/github.com/avast/retry-go/.travis.yml b/vendor/github.com/avast/retry-go/.travis.yml deleted file mode 100644 index ae3e0b688..000000000 --- a/vendor/github.com/avast/retry-go/.travis.yml +++ /dev/null @@ -1,20 +0,0 @@ -language: go - -go: - - 1.8 - - 1.9 - - "1.10" - - 1.11 - - 1.12 - - 1.13 - - 1.14 - - 1.15 - -install: - - make setup - -script: - - make ci - -after_success: - - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/github.com/avast/retry-go/Gopkg.toml b/vendor/github.com/avast/retry-go/Gopkg.toml deleted file mode 100644 index cf8c9eb0e..000000000 --- a/vendor/github.com/avast/retry-go/Gopkg.toml +++ /dev/null @@ -1,3 +0,0 @@ -[[constraint]] - name = "github.com/stretchr/testify" - version = "1.1.4" diff --git a/vendor/github.com/avast/retry-go/VERSION b/vendor/github.com/avast/retry-go/VERSION deleted file mode 100644 index 4a36342fc..000000000 --- a/vendor/github.com/avast/retry-go/VERSION +++ /dev/null @@ -1 +0,0 @@ -3.0.0 diff --git a/vendor/github.com/avast/retry-go/appveyor.yml b/vendor/github.com/avast/retry-go/appveyor.yml deleted file mode 100644 index dc5234ac8..000000000 --- a/vendor/github.com/avast/retry-go/appveyor.yml +++ /dev/null @@ -1,19 +0,0 @@ -version: "{build}" - -clone_folder: c:\Users\appveyor\go\src\github.com\avast\retry-go - -#os: Windows Server 2012 R2 -platform: x64 - -install: - - copy c:\MinGW\bin\mingw32-make.exe c:\MinGW\bin\make.exe - - set GOPATH=C:\Users\appveyor\go - - set PATH=%PATH%;c:\MinGW\bin - - set PATH=%PATH%;%GOPATH%\bin;c:\go\bin - - set GOBIN=%GOPATH%\bin - - go version - - go env - - make setup - -build_script: - - make ci diff --git a/vendor/github.com/avast/retry-go/retry.go b/vendor/github.com/avast/retry-go/retry.go deleted file mode 100644 index af2d92641..000000000 --- a/vendor/github.com/avast/retry-go/retry.go +++ /dev/null @@ -1,225 +0,0 @@ -/* -Simple library for retry mechanism - -slightly inspired by [Try::Tiny::Retry](https://metacpan.org/pod/Try::Tiny::Retry) - -SYNOPSIS - -http get with retry: - - url := "http://example.com" - var body []byte - - err := retry.Do( - func() error { - resp, err := http.Get(url) - if err != nil { - return err - } - defer resp.Body.Close() - body, err = ioutil.ReadAll(resp.Body) - if err != nil { - return err - } - - return nil - }, - ) - - fmt.Println(body) - -[next examples](https://github.com/avast/retry-go/tree/master/examples) - - -SEE ALSO - -* [giantswarm/retry-go](https://github.com/giantswarm/retry-go) - slightly complicated interface. - -* [sethgrid/pester](https://github.com/sethgrid/pester) - only http retry for http calls with retries and backoff - -* [cenkalti/backoff](https://github.com/cenkalti/backoff) - Go port of the exponential backoff algorithm from Google's HTTP Client Library for Java. Really complicated interface. - -* [rafaeljesus/retry-go](https://github.com/rafaeljesus/retry-go) - looks good, slightly similar as this package, don't have 'simple' `Retry` method - -* [matryer/try](https://github.com/matryer/try) - very popular package, nonintuitive interface (for me) - - -BREAKING CHANGES - -3.0.0 - -* `DelayTypeFunc` accepts a new parameter `err` - this breaking change affects only your custom Delay Functions. This change allow [make delay functions based on error](examples/delay_based_on_error_test.go). - - -1.0.2 -> 2.0.0 - -* argument of `retry.Delay` is final delay (no multiplication by `retry.Units` anymore) - -* function `retry.Units` are removed - -* [more about this breaking change](https://github.com/avast/retry-go/issues/7) - - -0.3.0 -> 1.0.0 - -* `retry.Retry` function are changed to `retry.Do` function - -* `retry.RetryCustom` (OnRetry) and `retry.RetryCustomWithOpts` functions are now implement via functions produces Options (aka `retry.OnRetry`) - - -*/ -package retry - -import ( - "context" - "fmt" - "strings" - "time" -) - -// Function signature of retryable function -type RetryableFunc func() error - -var ( - DefaultAttempts = uint(10) - DefaultDelay = 100 * time.Millisecond - DefaultMaxJitter = 100 * time.Millisecond - DefaultOnRetry = func(n uint, err error) {} - DefaultRetryIf = IsRecoverable - DefaultDelayType = CombineDelay(BackOffDelay, RandomDelay) - DefaultLastErrorOnly = false - DefaultContext = context.Background() -) - -func Do(retryableFunc RetryableFunc, opts ...Option) error { - var n uint - - //default - config := &Config{ - attempts: DefaultAttempts, - delay: DefaultDelay, - maxJitter: DefaultMaxJitter, - onRetry: DefaultOnRetry, - retryIf: DefaultRetryIf, - delayType: DefaultDelayType, - lastErrorOnly: DefaultLastErrorOnly, - context: DefaultContext, - } - - //apply opts - for _, opt := range opts { - opt(config) - } - - if err := config.context.Err(); err != nil { - return err - } - - var errorLog Error - if !config.lastErrorOnly { - errorLog = make(Error, config.attempts) - } else { - errorLog = make(Error, 1) - } - - lastErrIndex := n - for n < config.attempts { - err := retryableFunc() - - if err != nil { - errorLog[lastErrIndex] = unpackUnrecoverable(err) - - if !config.retryIf(err) { - break - } - - config.onRetry(n, err) - - // if this is last attempt - don't wait - if n == config.attempts-1 { - break - } - - delayTime := config.delayType(n, err, config) - if config.maxDelay > 0 && delayTime > config.maxDelay { - delayTime = config.maxDelay - } - - select { - case <-time.After(delayTime): - case <-config.context.Done(): - return config.context.Err() - } - - } else { - return nil - } - - n++ - if !config.lastErrorOnly { - lastErrIndex = n - } - } - - if config.lastErrorOnly { - return errorLog[lastErrIndex] - } - return errorLog -} - -// Error type represents list of errors in retry -type Error []error - -// Error method return string representation of Error -// It is an implementation of error interface -func (e Error) Error() string { - logWithNumber := make([]string, lenWithoutNil(e)) - for i, l := range e { - if l != nil { - logWithNumber[i] = fmt.Sprintf("#%d: %s", i+1, l.Error()) - } - } - - return fmt.Sprintf("All attempts fail:\n%s", strings.Join(logWithNumber, "\n")) -} - -func lenWithoutNil(e Error) (count int) { - for _, v := range e { - if v != nil { - count++ - } - } - - return -} - -// WrappedErrors returns the list of errors that this Error is wrapping. -// It is an implementation of the `errwrap.Wrapper` interface -// in package [errwrap](https://github.com/hashicorp/errwrap) so that -// `retry.Error` can be used with that library. -func (e Error) WrappedErrors() []error { - return e -} - -type unrecoverableError struct { - error -} - -// Unrecoverable wraps an error in `unrecoverableError` struct -func Unrecoverable(err error) error { - return unrecoverableError{err} -} - -// IsRecoverable checks if error is an instance of `unrecoverableError` -func IsRecoverable(err error) bool { - _, isUnrecoverable := err.(unrecoverableError) - return !isUnrecoverable -} - -func unpackUnrecoverable(err error) error { - if unrecoverable, isUnrecoverable := err.(unrecoverableError); isUnrecoverable { - return unrecoverable.error - } - - return err -} diff --git a/vendor/github.com/avast/retry-go/.gitignore b/vendor/github.com/avast/retry-go/v4/.gitignore similarity index 100% rename from vendor/github.com/avast/retry-go/.gitignore rename to vendor/github.com/avast/retry-go/v4/.gitignore diff --git a/vendor/github.com/avast/retry-go/.godocdown.tmpl b/vendor/github.com/avast/retry-go/v4/.godocdown.tmpl similarity index 85% rename from vendor/github.com/avast/retry-go/.godocdown.tmpl rename to vendor/github.com/avast/retry-go/v4/.godocdown.tmpl index 6873edf8e..e914ca4af 100644 --- a/vendor/github.com/avast/retry-go/.godocdown.tmpl +++ b/vendor/github.com/avast/retry-go/v4/.godocdown.tmpl @@ -2,8 +2,7 @@ [![Release](https://img.shields.io/github/release/avast/retry-go.svg?style=flat-square)](https://github.com/avast/retry-go/releases/latest) [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) -[![Travis](https://img.shields.io/travis/avast/retry-go.svg?style=flat-square)](https://travis-ci.org/avast/retry-go) -[![AppVeyor](https://ci.appveyor.com/api/projects/status/fieg9gon3qlq0a9a?svg=true)](https://ci.appveyor.com/project/JaSei/retry-go) +![GitHub Actions](https://github.com/avast/retry-go/actions/workflows/workflow.yaml/badge.svg) [![Go Report Card](https://goreportcard.com/badge/github.com/avast/retry-go?style=flat-square)](https://goreportcard.com/report/github.com/avast/retry-go) [![GoDoc](https://godoc.org/github.com/avast/retry-go?status.svg&style=flat-square)](http://godoc.org/github.com/avast/retry-go) [![codecov.io](https://codecov.io/github/avast/retry-go/coverage.svg?branch=master)](https://codecov.io/github/avast/retry-go?branch=master) @@ -25,6 +24,8 @@ Try `make help` for more information. ### Before pull request +> maybe you need `make setup` in order to setup environment + please try: * run tests (`make test`) * run linter (`make lint`) diff --git a/vendor/github.com/avast/retry-go/LICENSE b/vendor/github.com/avast/retry-go/v4/LICENSE similarity index 100% rename from vendor/github.com/avast/retry-go/LICENSE rename to vendor/github.com/avast/retry-go/v4/LICENSE diff --git a/vendor/github.com/avast/retry-go/Makefile b/vendor/github.com/avast/retry-go/v4/Makefile similarity index 83% rename from vendor/github.com/avast/retry-go/Makefile rename to vendor/github.com/avast/retry-go/v4/Makefile index 769816d24..86544d239 100644 --- a/vendor/github.com/avast/retry-go/Makefile +++ b/vendor/github.com/avast/retry-go/v4/Makefile @@ -1,37 +1,26 @@ SOURCE_FILES?=$$(go list ./... | grep -v /vendor/) TEST_PATTERN?=. TEST_OPTIONS?= -DEP?=$$(which dep) VERSION?=$$(cat VERSION) LINTER?=$$(which golangci-lint) -LINTER_VERSION=1.15.0 +LINTER_VERSION=1.50.0 ifeq ($(OS),Windows_NT) - DEP_VERS=dep-windows-amd64 LINTER_FILE=golangci-lint-$(LINTER_VERSION)-windows-amd64.zip LINTER_UNPACK= >| app.zip; unzip -j app.zip -d $$GOPATH/bin; rm app.zip else ifeq ($(OS), Darwin) LINTER_FILE=golangci-lint-$(LINTER_VERSION)-darwin-amd64.tar.gz LINTER_UNPACK= | tar xzf - -C $$GOPATH/bin --wildcards --strip 1 "**/golangci-lint" else - DEP_VERS=dep-linux-amd64 LINTER_FILE=golangci-lint-$(LINTER_VERSION)-linux-amd64.tar.gz LINTER_UNPACK= | tar xzf - -C $$GOPATH/bin --wildcards --strip 1 "**/golangci-lint" endif setup: - go get -u github.com/pierrre/gotestcover - go get -u golang.org/x/tools/cmd/cover - go get -u github.com/robertkrimen/godocdown/godocdown - @if [ "$(LINTER)" = "" ]; then\ - curl -L https://github.com/golangci/golangci-lint/releases/download/v$(LINTER_VERSION)/$(LINTER_FILE) $(LINTER_UNPACK) ;\ - chmod +x $$GOPATH/bin/golangci-lint;\ - fi - @if [ "$(DEP)" = "" ]; then\ - curl -L https://github.com/golang/dep/releases/download/v0.3.1/$(DEP_VERS) >| $$GOPATH/bin/dep;\ - chmod +x $$GOPATH/bin/dep;\ - fi - dep ensure + go install github.com/pierrre/gotestcover@latest + go install golang.org/x/tools/cmd/cover@latest + go install github.com/robertkrimen/godocdown/godocdown@latest + go mod download generate: ## Generate README.md godocdown >| README.md @@ -48,6 +37,11 @@ fmt: ## gofmt and goimports all go files find . -name '*.go' -not -wholename './vendor/*' | while read -r file; do gofmt -w -s "$$file"; goimports -w "$$file"; done lint: ## Run all the linters + @if [ "$(LINTER)" = "" ]; then\ + curl -L https://github.com/golangci/golangci-lint/releases/download/v$(LINTER_VERSION)/$(LINTER_FILE) $(LINTER_UNPACK) ;\ + chmod +x $$GOPATH/bin/golangci-lint;\ + fi + golangci-lint run ci: test_and_cover_report ## Run all the tests but no linters - use https://golangci.com integration instead diff --git a/vendor/github.com/avast/retry-go/README.md b/vendor/github.com/avast/retry-go/v4/README.md similarity index 64% rename from vendor/github.com/avast/retry-go/README.md rename to vendor/github.com/avast/retry-go/v4/README.md index 80fb73b4b..da8e54757 100644 --- a/vendor/github.com/avast/retry-go/README.md +++ b/vendor/github.com/avast/retry-go/v4/README.md @@ -2,8 +2,7 @@ [![Release](https://img.shields.io/github/release/avast/retry-go.svg?style=flat-square)](https://github.com/avast/retry-go/releases/latest) [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) -[![Travis](https://img.shields.io/travis/avast/retry-go.svg?style=flat-square)](https://travis-ci.org/avast/retry-go) -[![AppVeyor](https://ci.appveyor.com/api/projects/status/fieg9gon3qlq0a9a?svg=true)](https://ci.appveyor.com/project/JaSei/retry-go) +![GitHub Actions](https://github.com/avast/retry-go/actions/workflows/workflow.yaml/badge.svg) [![Go Report Card](https://goreportcard.com/badge/github.com/avast/retry-go?style=flat-square)](https://goreportcard.com/report/github.com/avast/retry-go) [![GoDoc](https://godoc.org/github.com/avast/retry-go?status.svg&style=flat-square)](http://godoc.org/github.com/avast/retry-go) [![codecov.io](https://codecov.io/github/avast/retry-go/coverage.svg?branch=master)](https://codecov.io/github/avast/retry-go?branch=master) @@ -14,8 +13,7 @@ Simple library for retry mechanism slightly inspired by [Try::Tiny::Retry](https://metacpan.org/pod/Try::Tiny::Retry) - -### SYNOPSIS +# SYNOPSIS http get with retry: @@ -37,13 +35,40 @@ http get with retry: return nil }, ) + if err != nil { + // handle error + } - fmt.Println(body) + fmt.Println(string(body)) -[next examples](https://github.com/avast/retry-go/tree/master/examples) +http get with retry with data: + url := "http://example.com" -### SEE ALSO + body, err := retry.DoWithData( + func() ([]byte, error) { + resp, err := http.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + return body, nil + }, + ) + if err != nil { + // handle error + } + + fmt.Println(string(body)) + +[next examples](https://github.com/avast/retry-go/tree/master/examples) + +# SEE ALSO * [giantswarm/retry-go](https://github.com/giantswarm/retry-go) - slightly complicated interface. @@ -61,46 +86,29 @@ slightly similar as this package, don't have 'simple' `Retry` method * [matryer/try](https://github.com/matryer/try) - very popular package, nonintuitive interface (for me) +# BREAKING CHANGES -### BREAKING CHANGES +* 4.0.0 -3.0.0 + - infinity retry is possible by set `Attempts(0)` by PR [#49](https://github.com/avast/retry-go/pull/49) -* `DelayTypeFunc` accepts a new parameter `err` - this breaking change affects -only your custom Delay Functions. This change allow [make delay functions based -on error](examples/delay_based_on_error_test.go). +* 3.0.0 -1.0.2 -> 2.0.0 + - `DelayTypeFunc` accepts a new parameter `err` - this breaking change affects only your custom Delay Functions. This change allow [make delay functions based on error](examples/delay_based_on_error_test.go). -* argument of `retry.Delay` is final delay (no multiplication by `retry.Units` -anymore) +* 1.0.2 -> 2.0.0 -* function `retry.Units` are removed + - argument of `retry.Delay` is final delay (no multiplication by `retry.Units` anymore) + - function `retry.Units` are removed + - [more about this breaking change](https://github.com/avast/retry-go/issues/7) -* [more about this breaking change](https://github.com/avast/retry-go/issues/7) +* 0.3.0 -> 1.0.0 -0.3.0 -> 1.0.0 - -* `retry.Retry` function are changed to `retry.Do` function - -* `retry.RetryCustom` (OnRetry) and `retry.RetryCustomWithOpts` functions are -now implement via functions produces Options (aka `retry.OnRetry`) + - `retry.Retry` function are changed to `retry.Do` function + - `retry.RetryCustom` (OnRetry) and `retry.RetryCustomWithOpts` functions are now implement via functions produces Options (aka `retry.OnRetry`) ## Usage -```go -var ( - DefaultAttempts = uint(10) - DefaultDelay = 100 * time.Millisecond - DefaultMaxJitter = 100 * time.Millisecond - DefaultOnRetry = func(n uint, err error) {} - DefaultRetryIf = IsRecoverable - DefaultDelayType = CombineDelay(BackOffDelay, RandomDelay) - DefaultLastErrorOnly = false - DefaultContext = context.Background() -) -``` - #### func BackOffDelay ```go @@ -114,6 +122,12 @@ BackOffDelay is a DelayType which increases delay between consecutive retries func Do(retryableFunc RetryableFunc, opts ...Option) error ``` +#### func DoWithData + +```go +func DoWithData[T any](retryableFunc RetryableFuncWithData[T], opts ...Option) (T, error) +``` + #### func FixedDelay ```go @@ -175,6 +189,12 @@ type Error []error Error type represents list of errors in retry +#### func (Error) As + +```go +func (e Error) As(target interface{}) bool +``` + #### func (Error) Error ```go @@ -183,6 +203,31 @@ func (e Error) Error() string Error method return string representation of Error It is an implementation of error interface +#### func (Error) Is + +```go +func (e Error) Is(target error) bool +``` + +#### func (Error) Unwrap + +```go +func (e Error) Unwrap() error +``` +Unwrap the last error for compatibility with `errors.Unwrap()`. When you need to +unwrap all errors, you should use `WrappedErrors()` instead. + + err := Do( + func() error { + return errors.New("original error") + }, + Attempts(1), + ) + + fmt.Println(errors.Unwrap(err)) # "original error" is printed + +Added in version 4.2.0. + #### func (Error) WrappedErrors ```go @@ -214,7 +259,19 @@ Option represents an option for retry. ```go func Attempts(attempts uint) Option ``` -Attempts set count of retry default is 10 +Attempts set count of retry. Setting to 0 will retry until the retried function +succeeds. default is 10 + +#### func AttemptsForError + +```go +func AttemptsForError(attempts uint, err error) Option +``` +AttemptsForError sets count of retry in case execution results in given `err` +Retries for the given `err` are also counted against total retries. The retry +will stop if any of given retries is exhausted. + +added in 4.3.0 #### func Context @@ -321,6 +378,53 @@ By default RetryIf stops execution if the error is wrapped using } ) +#### func WithTimer + +```go +func WithTimer(t Timer) Option +``` +WithTimer provides a way to swap out timer module implementations. This +primarily is useful for mocking/testing, where you may not want to explicitly +wait for a set duration for retries. + +example of augmenting time.After with a print statement + + type struct MyTimer {} + + func (t *MyTimer) After(d time.Duration) <- chan time.Time { + fmt.Print("Timer called!") + return time.After(d) + } + + retry.Do( + func() error { ... }, + retry.WithTimer(&MyTimer{}) + ) + +#### func WrapContextErrorWithLastError + +```go +func WrapContextErrorWithLastError(wrapContextErrorWithLastError bool) Option +``` +WrapContextErrorWithLastError allows the context error to be returned wrapped +with the last error that the retried function returned. This is only applicable +when Attempts is set to 0 to retry indefinitly and when using a context to +cancel / timeout + +default is false + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + retry.Do( + func() error { + ... + }, + retry.Context(ctx), + retry.Attempts(0), + retry.WrapContextErrorWithLastError(true), + ) + #### type RetryIfFunc ```go @@ -337,6 +441,24 @@ type RetryableFunc func() error Function signature of retryable function +#### type RetryableFuncWithData + +```go +type RetryableFuncWithData[T any] func() (T, error) +``` + +Function signature of retryable function with data + +#### type Timer + +```go +type Timer interface { + After(time.Duration) <-chan time.Time +} +``` + +Timer represents the timer used to track time for a retry. + ## Contributing Contributions are very much welcome. @@ -349,6 +471,8 @@ Try `make help` for more information. ### Before pull request +> maybe you need `make setup` in order to setup environment + please try: * run tests (`make test`) * run linter (`make lint`) diff --git a/vendor/github.com/avast/retry-go/v4/VERSION b/vendor/github.com/avast/retry-go/v4/VERSION new file mode 100644 index 000000000..a84947d6f --- /dev/null +++ b/vendor/github.com/avast/retry-go/v4/VERSION @@ -0,0 +1 @@ +4.5.0 diff --git a/vendor/github.com/avast/retry-go/options.go b/vendor/github.com/avast/retry-go/v4/options.go similarity index 63% rename from vendor/github.com/avast/retry-go/options.go rename to vendor/github.com/avast/retry-go/v4/options.go index a6c57207c..9d98a1d43 100644 --- a/vendor/github.com/avast/retry-go/options.go +++ b/vendor/github.com/avast/retry-go/v4/options.go @@ -17,16 +17,24 @@ type OnRetryFunc func(n uint, err error) // DelayTypeFunc is called to return the next delay to wait after the retriable function fails on `err` after `n` attempts. type DelayTypeFunc func(n uint, err error, config *Config) time.Duration +// Timer represents the timer used to track time for a retry. +type Timer interface { + After(time.Duration) <-chan time.Time +} + type Config struct { - attempts uint - delay time.Duration - maxDelay time.Duration - maxJitter time.Duration - onRetry OnRetryFunc - retryIf RetryIfFunc - delayType DelayTypeFunc - lastErrorOnly bool - context context.Context + attempts uint + attemptsForError map[error]uint + delay time.Duration + maxDelay time.Duration + maxJitter time.Duration + onRetry OnRetryFunc + retryIf RetryIfFunc + delayType DelayTypeFunc + lastErrorOnly bool + context context.Context + timer Timer + wrapContextErrorWithLastError bool maxBackOffN uint } @@ -34,6 +42,8 @@ type Config struct { // Option represents an option for retry. type Option func(*Config) +func emptyOption(c *Config) {} + // return the direct last error that came from the retried function // default is false (return wrapped errors with everything) func LastErrorOnly(lastErrorOnly bool) Option { @@ -42,7 +52,7 @@ func LastErrorOnly(lastErrorOnly bool) Option { } } -// Attempts set count of retry +// Attempts set count of retry. Setting to 0 will retry until the retried function succeeds. // default is 10 func Attempts(attempts uint) Option { return func(c *Config) { @@ -50,6 +60,17 @@ func Attempts(attempts uint) Option { } } +// AttemptsForError sets count of retry in case execution results in given `err` +// Retries for the given `err` are also counted against total retries. +// The retry will stop if any of given retries is exhausted. +// +// added in 4.3.0 +func AttemptsForError(attempts uint, err error) Option { + return func(c *Config) { + c.attemptsForError[err] = attempts + } +} + // Delay set delay between retry // default is 100ms func Delay(delay time.Duration) Option { @@ -76,6 +97,9 @@ func MaxJitter(maxJitter time.Duration) Option { // DelayType set type of the delay between retries // default is BackOff func DelayType(delayType DelayTypeFunc) Option { + if delayType == nil { + return emptyOption + } return func(c *Config) { c.delayType = delayType } @@ -141,6 +165,9 @@ func CombineDelay(delays ...DelayTypeFunc) DelayTypeFunc { // }), // ) func OnRetry(onRetry OnRetryFunc) Option { + if onRetry == nil { + return emptyOption + } return func(c *Config) { c.onRetry = onRetry } @@ -172,6 +199,9 @@ func OnRetry(onRetry OnRetryFunc) Option { // } // ) func RetryIf(retryIf RetryIfFunc) Option { + if retryIf == nil { + return emptyOption + } return func(c *Config) { c.retryIf = retryIf } @@ -196,3 +226,49 @@ func Context(ctx context.Context) Option { c.context = ctx } } + +// WithTimer provides a way to swap out timer module implementations. +// This primarily is useful for mocking/testing, where you may not want to explicitly wait for a set duration +// for retries. +// +// example of augmenting time.After with a print statement +// +// type struct MyTimer {} +// +// func (t *MyTimer) After(d time.Duration) <- chan time.Time { +// fmt.Print("Timer called!") +// return time.After(d) +// } +// +// retry.Do( +// func() error { ... }, +// retry.WithTimer(&MyTimer{}) +// ) +func WithTimer(t Timer) Option { + return func(c *Config) { + c.timer = t + } +} + +// WrapContextErrorWithLastError allows the context error to be returned wrapped with the last error that the +// retried function returned. This is only applicable when Attempts is set to 0 to retry indefinitly and when +// using a context to cancel / timeout +// +// default is false +// +// ctx, cancel := context.WithCancel(context.Background()) +// defer cancel() +// +// retry.Do( +// func() error { +// ... +// }, +// retry.Context(ctx), +// retry.Attempts(0), +// retry.WrapContextErrorWithLastError(true), +// ) +func WrapContextErrorWithLastError(wrapContextErrorWithLastError bool) Option { + return func(c *Config) { + c.wrapContextErrorWithLastError = wrapContextErrorWithLastError + } +} diff --git a/vendor/github.com/avast/retry-go/v4/retry.go b/vendor/github.com/avast/retry-go/v4/retry.go new file mode 100644 index 000000000..b5d49d546 --- /dev/null +++ b/vendor/github.com/avast/retry-go/v4/retry.go @@ -0,0 +1,340 @@ +/* +Simple library for retry mechanism + +slightly inspired by [Try::Tiny::Retry](https://metacpan.org/pod/Try::Tiny::Retry) + +# SYNOPSIS + +http get with retry: + + url := "http://example.com" + var body []byte + + err := retry.Do( + func() error { + resp, err := http.Get(url) + if err != nil { + return err + } + defer resp.Body.Close() + body, err = ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + + return nil + }, + ) + if err != nil { + // handle error + } + + fmt.Println(string(body)) + +http get with retry with data: + + url := "http://example.com" + + body, err := retry.DoWithData( + func() ([]byte, error) { + resp, err := http.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + return body, nil + }, + ) + if err != nil { + // handle error + } + + fmt.Println(string(body)) + +[next examples](https://github.com/avast/retry-go/tree/master/examples) + +# SEE ALSO + +* [giantswarm/retry-go](https://github.com/giantswarm/retry-go) - slightly complicated interface. + +* [sethgrid/pester](https://github.com/sethgrid/pester) - only http retry for http calls with retries and backoff + +* [cenkalti/backoff](https://github.com/cenkalti/backoff) - Go port of the exponential backoff algorithm from Google's HTTP Client Library for Java. Really complicated interface. + +* [rafaeljesus/retry-go](https://github.com/rafaeljesus/retry-go) - looks good, slightly similar as this package, don't have 'simple' `Retry` method + +* [matryer/try](https://github.com/matryer/try) - very popular package, nonintuitive interface (for me) + +# BREAKING CHANGES + +* 4.0.0 + - infinity retry is possible by set `Attempts(0)` by PR [#49](https://github.com/avast/retry-go/pull/49) + +* 3.0.0 + - `DelayTypeFunc` accepts a new parameter `err` - this breaking change affects only your custom Delay Functions. This change allow [make delay functions based on error](examples/delay_based_on_error_test.go). + +* 1.0.2 -> 2.0.0 + - argument of `retry.Delay` is final delay (no multiplication by `retry.Units` anymore) + - function `retry.Units` are removed + - [more about this breaking change](https://github.com/avast/retry-go/issues/7) + +* 0.3.0 -> 1.0.0 + - `retry.Retry` function are changed to `retry.Do` function + - `retry.RetryCustom` (OnRetry) and `retry.RetryCustomWithOpts` functions are now implement via functions produces Options (aka `retry.OnRetry`) +*/ +package retry + +import ( + "context" + "errors" + "fmt" + "strings" + "time" +) + +// Function signature of retryable function +type RetryableFunc func() error + +// Function signature of retryable function with data +type RetryableFuncWithData[T any] func() (T, error) + +// Default timer is a wrapper around time.After +type timerImpl struct{} + +func (t *timerImpl) After(d time.Duration) <-chan time.Time { + return time.After(d) +} + +func Do(retryableFunc RetryableFunc, opts ...Option) error { + retryableFuncWithData := func() (any, error) { + return nil, retryableFunc() + } + + _, err := DoWithData(retryableFuncWithData, opts...) + return err +} + +func DoWithData[T any](retryableFunc RetryableFuncWithData[T], opts ...Option) (T, error) { + var n uint + var emptyT T + + // default + config := newDefaultRetryConfig() + + // apply opts + for _, opt := range opts { + opt(config) + } + + if err := config.context.Err(); err != nil { + return emptyT, err + } + + // Setting attempts to 0 means we'll retry until we succeed + var lastErr error + if config.attempts == 0 { + for { + t, err := retryableFunc() + if err == nil { + return t, nil + } + + if !IsRecoverable(err) { + return emptyT, err + } + + if !config.retryIf(err) { + return emptyT, err + } + + lastErr = err + + n++ + config.onRetry(n, err) + select { + case <-config.timer.After(delay(config, n, err)): + case <-config.context.Done(): + if config.wrapContextErrorWithLastError { + return emptyT, Error{config.context.Err(), lastErr} + } + return emptyT, config.context.Err() + } + } + } + + errorLog := Error{} + + attemptsForError := make(map[error]uint, len(config.attemptsForError)) + for err, attempts := range config.attemptsForError { + attemptsForError[err] = attempts + } + + shouldRetry := true + for shouldRetry { + t, err := retryableFunc() + if err == nil { + return t, nil + } + + errorLog = append(errorLog, unpackUnrecoverable(err)) + + if !config.retryIf(err) { + break + } + + config.onRetry(n, err) + + for errToCheck, attempts := range attemptsForError { + if errors.Is(err, errToCheck) { + attempts-- + attemptsForError[errToCheck] = attempts + shouldRetry = shouldRetry && attempts > 0 + } + } + + // if this is last attempt - don't wait + if n == config.attempts-1 { + break + } + + select { + case <-config.timer.After(delay(config, n, err)): + case <-config.context.Done(): + if config.lastErrorOnly { + return emptyT, config.context.Err() + } + + return emptyT, append(errorLog, config.context.Err()) + } + + n++ + shouldRetry = shouldRetry && n < config.attempts + } + + if config.lastErrorOnly { + return emptyT, errorLog.Unwrap() + } + return emptyT, errorLog +} + +func newDefaultRetryConfig() *Config { + return &Config{ + attempts: uint(10), + attemptsForError: make(map[error]uint), + delay: 100 * time.Millisecond, + maxJitter: 100 * time.Millisecond, + onRetry: func(n uint, err error) {}, + retryIf: IsRecoverable, + delayType: CombineDelay(BackOffDelay, RandomDelay), + lastErrorOnly: false, + context: context.Background(), + timer: &timerImpl{}, + } +} + +// Error type represents list of errors in retry +type Error []error + +// Error method return string representation of Error +// It is an implementation of error interface +func (e Error) Error() string { + logWithNumber := make([]string, len(e)) + for i, l := range e { + if l != nil { + logWithNumber[i] = fmt.Sprintf("#%d: %s", i+1, l.Error()) + } + } + + return fmt.Sprintf("All attempts fail:\n%s", strings.Join(logWithNumber, "\n")) +} + +func (e Error) Is(target error) bool { + for _, v := range e { + if errors.Is(v, target) { + return true + } + } + return false +} + +func (e Error) As(target interface{}) bool { + for _, v := range e { + if errors.As(v, target) { + return true + } + } + return false +} + +/* +Unwrap the last error for compatibility with `errors.Unwrap()`. +When you need to unwrap all errors, you should use `WrappedErrors()` instead. + + err := Do( + func() error { + return errors.New("original error") + }, + Attempts(1), + ) + + fmt.Println(errors.Unwrap(err)) # "original error" is printed + +Added in version 4.2.0. +*/ +func (e Error) Unwrap() error { + return e[len(e)-1] +} + +// WrappedErrors returns the list of errors that this Error is wrapping. +// It is an implementation of the `errwrap.Wrapper` interface +// in package [errwrap](https://github.com/hashicorp/errwrap) so that +// `retry.Error` can be used with that library. +func (e Error) WrappedErrors() []error { + return e +} + +type unrecoverableError struct { + error +} + +func (e unrecoverableError) Unwrap() error { + return e.error +} + +// Unrecoverable wraps an error in `unrecoverableError` struct +func Unrecoverable(err error) error { + return unrecoverableError{err} +} + +// IsRecoverable checks if error is an instance of `unrecoverableError` +func IsRecoverable(err error) bool { + return !errors.Is(err, unrecoverableError{}) +} + +// Adds support for errors.Is usage on unrecoverableError +func (unrecoverableError) Is(err error) bool { + _, isUnrecoverable := err.(unrecoverableError) + return isUnrecoverable +} + +func unpackUnrecoverable(err error) error { + if unrecoverable, isUnrecoverable := err.(unrecoverableError); isUnrecoverable { + return unrecoverable.error + } + + return err +} + +func delay(config *Config, n uint, err error) time.Duration { + delayTime := config.delayType(n, err, config) + if config.maxDelay > 0 && delayTime > config.maxDelay { + delayTime = config.maxDelay + } + + return delayTime +} diff --git a/vendor/modules.txt b/vendor/modules.txt index e6c0147b0..0c87b764f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -26,9 +26,9 @@ contrib.go.opencensus.io/exporter/stackdriver/monitoredresource/gcp # github.com/acobaugh/osrelease v0.1.0 ## explicit; go 1.17 github.com/acobaugh/osrelease -# github.com/avast/retry-go v3.0.0+incompatible -## explicit -github.com/avast/retry-go +# github.com/avast/retry-go/v4 v4.5.0 +## explicit; go 1.18 +github.com/avast/retry-go/v4 # github.com/aws/aws-sdk-go v1.44.72 ## explicit; go 1.11 github.com/aws/aws-sdk-go/aws