Compare commits
No commits in common. "master" and "v0.2.0" have entirely different histories.
@ -13,7 +13,6 @@ import (
|
|||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
@ -74,17 +73,11 @@ type CalendarHandler struct{}
|
|||||||
|
|
||||||
func (c *CalendarHandler) ServeHTTP(w http.ResponseWriter, _ *http.Request) {
|
func (c *CalendarHandler) ServeHTTP(w http.ResponseWriter, _ *http.Request) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
calDavHolidays, err := cal.IsHolidaysFromCaldav(now)
|
|
||||||
if err != nil {
|
|
||||||
zap.S().Warnf("unable to read holiday status from caldav: %v", err)
|
|
||||||
calDavHolidays = false
|
|
||||||
}
|
|
||||||
|
|
||||||
cd := CalendarDay{
|
cd := CalendarDay{
|
||||||
Day: now,
|
Day: now,
|
||||||
WorkingDay: cal.IsWorkingDay(now),
|
WorkingDay: cal.IsWorkingDay(now),
|
||||||
Ferie: cal.IsHoliday(now),
|
Ferie: cal.IsHoliday(now),
|
||||||
Holiday: calDavHolidays,
|
Holiday: cal.IsHoliday(now),
|
||||||
Weekday: cal.IsWeekDay(now),
|
Weekday: cal.IsWeekDay(now),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +97,6 @@ func (c *CalendarHandler) ServeHTTP(w http.ResponseWriter, _ *http.Request) {
|
|||||||
func main() {
|
func main() {
|
||||||
var port int
|
var port int
|
||||||
var host string
|
var host string
|
||||||
var user, pwd string
|
|
||||||
var caldavUrl, caldavPath, caldavSummaryPattern string
|
var caldavUrl, caldavPath, caldavSummaryPattern string
|
||||||
|
|
||||||
flag.StringVar(&host, "host", "", "host to listen, default all addresses")
|
flag.StringVar(&host, "host", "", "host to listen, default all addresses")
|
||||||
@ -112,8 +104,6 @@ func main() {
|
|||||||
flag.StringVar(&caldavUrl, "caldav-url", "", "caldav url to use to read holidays events")
|
flag.StringVar(&caldavUrl, "caldav-url", "", "caldav url to use to read holidays events")
|
||||||
flag.StringVar(&caldavPath, "caldav-path", "", "caldav path to use to read holidays events")
|
flag.StringVar(&caldavPath, "caldav-path", "", "caldav path to use to read holidays events")
|
||||||
flag.StringVar(&caldavSummaryPattern, "caldav-summary-pattern", "Holidays", "Summary pattern that matches holidays event")
|
flag.StringVar(&caldavSummaryPattern, "caldav-summary-pattern", "Holidays", "Summary pattern that matches holidays event")
|
||||||
flag.StringVar(&user, "caldav-username", "", "Username credential")
|
|
||||||
flag.StringVar(&pwd, "caldav-password", "", "Password credential")
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
logLevel := zap.LevelFlag("log", zap.InfoLevel, "log level")
|
logLevel := zap.LevelFlag("log", zap.InfoLevel, "log level")
|
||||||
@ -135,13 +125,7 @@ func main() {
|
|||||||
}()
|
}()
|
||||||
zap.ReplaceGlobals(lgr)
|
zap.ReplaceGlobals(lgr)
|
||||||
|
|
||||||
urlCaldav, err := url.Parse(caldavUrl)
|
cdav, err := calendar.NewCaldav(caldavUrl, caldavPath)
|
||||||
if err != nil {
|
|
||||||
zap.S().Panicf("invalid caldav url '%v': %v", caldavUrl, err)
|
|
||||||
}
|
|
||||||
urlCaldav.User = url.UserPassword(user, pwd)
|
|
||||||
|
|
||||||
cdav, err := calendar.NewCaldav(urlCaldav.String(), caldavPath)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
zap.S().Fatal("unable to init caldav instance")
|
zap.S().Fatal("unable to init caldav instance")
|
||||||
}
|
}
|
||||||
@ -177,9 +161,6 @@ func main() {
|
|||||||
SkipOnErr: false,
|
SkipOnErr: false,
|
||||||
Check: func(ctx context.Context) error {
|
Check: func(ctx context.Context) error {
|
||||||
_, err := cal.IsHolidaysFromCaldav(time.Now())
|
_, err := cal.IsHolidaysFromCaldav(time.Now())
|
||||||
if err != nil {
|
|
||||||
zap.S().Warnf("unable to check caldav connection: %v", err)
|
|
||||||
}
|
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
1
go.mod
1
go.mod
@ -3,7 +3,6 @@ module domogeek
|
|||||||
go 1.18
|
go 1.18
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/avast/retry-go v2.7.0+incompatible
|
|
||||||
github.com/dolanor/caldav-go v0.2.1
|
github.com/dolanor/caldav-go v0.2.1
|
||||||
github.com/hellofresh/health-go/v4 v4.5.0
|
github.com/hellofresh/health-go/v4 v4.5.0
|
||||||
github.com/prometheus/client_golang v1.12.1
|
github.com/prometheus/client_golang v1.12.1
|
||||||
|
2
go.sum
2
go.sum
@ -39,8 +39,6 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
|
|||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||||
github.com/avast/retry-go v2.7.0+incompatible h1:XaGnzl7gESAideSjr+I8Hki/JBi+Yb9baHlMRPeSC84=
|
|
||||||
github.com/avast/retry-go v2.7.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
|
|
||||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
|
@ -2,7 +2,6 @@ package calendar
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/avast/retry-go"
|
|
||||||
"github.com/dolanor/caldav-go/caldav"
|
"github.com/dolanor/caldav-go/caldav"
|
||||||
"github.com/dolanor/caldav-go/caldav/entities"
|
"github.com/dolanor/caldav-go/caldav/entities"
|
||||||
"github.com/dolanor/caldav-go/icalendar/components"
|
"github.com/dolanor/caldav-go/icalendar/components"
|
||||||
@ -29,26 +28,10 @@ func NewCaldav(caldavUrl, caldavPath string) (Caldav, error) {
|
|||||||
server, _ := caldav.NewServer(caldavUrl)
|
server, _ := caldav.NewServer(caldavUrl)
|
||||||
// create a CalDAV client to speak to the server
|
// create a CalDAV client to speak to the server
|
||||||
var client = caldav.NewClient(server, http.DefaultClient)
|
var client = caldav.NewClient(server, http.DefaultClient)
|
||||||
err := retry.Do(
|
// start executing requests!
|
||||||
func() error {
|
err := client.ValidateServer(caldavPath)
|
||||||
// start executing requests!
|
|
||||||
err := client.ValidateServer(caldavPath)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("bad caldav configuration, unable to validate connexion: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
retry.OnRetry(
|
|
||||||
func(n uint, err error) {
|
|
||||||
zap.S().Errorf("unable to validate caldav connection on retry %d: %v", n, err)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
retry.Attempts(1000),
|
|
||||||
retry.DelayType(retry.BackOffDelay),
|
|
||||||
retry.MaxDelay(24*time.Hour),
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to validate caldav connection: %w", err)
|
return nil, fmt.Errorf("bad caldav configuration, unable to validate connexion: %w", err)
|
||||||
}
|
}
|
||||||
return client, nil
|
return client, nil
|
||||||
}
|
}
|
||||||
|
21
vendor/github.com/avast/retry-go/.gitignore
generated
vendored
21
vendor/github.com/avast/retry-go/.gitignore
generated
vendored
@ -1,21 +0,0 @@
|
|||||||
# Binaries for programs and plugins
|
|
||||||
*.exe
|
|
||||||
*.dll
|
|
||||||
*.so
|
|
||||||
*.dylib
|
|
||||||
|
|
||||||
# Test binary, build with `go test -c`
|
|
||||||
*.test
|
|
||||||
|
|
||||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
|
||||||
*.out
|
|
||||||
|
|
||||||
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
|
|
||||||
.glide/
|
|
||||||
|
|
||||||
# dep
|
|
||||||
vendor/
|
|
||||||
Gopkg.lock
|
|
||||||
|
|
||||||
# cover
|
|
||||||
coverage.txt
|
|
37
vendor/github.com/avast/retry-go/.godocdown.tmpl
generated
vendored
37
vendor/github.com/avast/retry-go/.godocdown.tmpl
generated
vendored
@ -1,37 +0,0 @@
|
|||||||
# {{ .Name }}
|
|
||||||
|
|
||||||
[](https://github.com/avast/retry-go/releases/latest)
|
|
||||||
[](LICENSE.md)
|
|
||||||
[](https://travis-ci.org/avast/retry-go)
|
|
||||||
[](https://ci.appveyor.com/project/JaSei/retry-go)
|
|
||||||
[](https://goreportcard.com/report/github.com/avast/retry-go)
|
|
||||||
[](http://godoc.org/github.com/avast/retry-go)
|
|
||||||
[](https://codecov.io/github/avast/retry-go?branch=master)
|
|
||||||
[](https://sourcegraph.com/github.com/avast/retry-go?badge)
|
|
||||||
|
|
||||||
{{ .EmitSynopsis }}
|
|
||||||
|
|
||||||
{{ .EmitUsage }}
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
Contributions are very much welcome.
|
|
||||||
|
|
||||||
### Makefile
|
|
||||||
|
|
||||||
Makefile provides several handy rules, like README.md `generator` , `setup` for prepare build/dev environment, `test`, `cover`, etc...
|
|
||||||
|
|
||||||
Try `make help` for more information.
|
|
||||||
|
|
||||||
### Before pull request
|
|
||||||
|
|
||||||
please try:
|
|
||||||
* run tests (`make test`)
|
|
||||||
* run linter (`make lint`)
|
|
||||||
* if your IDE don't automaticaly do `go fmt`, run `go fmt` (`make fmt`)
|
|
||||||
|
|
||||||
### README
|
|
||||||
|
|
||||||
README.md are generate from template [.godocdown.tmpl](.godocdown.tmpl) and code documentation via [godocdown](https://github.com/robertkrimen/godocdown).
|
|
||||||
|
|
||||||
Never edit README.md direct, because your change will be lost.
|
|
21
vendor/github.com/avast/retry-go/.travis.yml
generated
vendored
21
vendor/github.com/avast/retry-go/.travis.yml
generated
vendored
@ -1,21 +0,0 @@
|
|||||||
language: go
|
|
||||||
|
|
||||||
go:
|
|
||||||
- 1.7
|
|
||||||
- 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)
|
|
3
vendor/github.com/avast/retry-go/Gopkg.toml
generated
vendored
3
vendor/github.com/avast/retry-go/Gopkg.toml
generated
vendored
@ -1,3 +0,0 @@
|
|||||||
[[constraint]]
|
|
||||||
name = "github.com/stretchr/testify"
|
|
||||||
version = "1.1.4"
|
|
21
vendor/github.com/avast/retry-go/LICENSE
generated
vendored
21
vendor/github.com/avast/retry-go/LICENSE
generated
vendored
@ -1,21 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2017 Avast
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
65
vendor/github.com/avast/retry-go/Makefile
generated
vendored
65
vendor/github.com/avast/retry-go/Makefile
generated
vendored
@ -1,65 +0,0 @@
|
|||||||
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
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
generate: ## Generate README.md
|
|
||||||
godocdown >| README.md
|
|
||||||
|
|
||||||
test: generate test_and_cover_report lint
|
|
||||||
|
|
||||||
test_and_cover_report:
|
|
||||||
gotestcover $(TEST_OPTIONS) -covermode=atomic -coverprofile=coverage.txt $(SOURCE_FILES) -run $(TEST_PATTERN) -timeout=2m
|
|
||||||
|
|
||||||
cover: test ## Run all the tests and opens the coverage report
|
|
||||||
go tool cover -html=coverage.txt
|
|
||||||
|
|
||||||
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
|
|
||||||
golangci-lint run
|
|
||||||
|
|
||||||
ci: test_and_cover_report ## Run all the tests but no linters - use https://golangci.com integration instead
|
|
||||||
|
|
||||||
build:
|
|
||||||
go build
|
|
||||||
|
|
||||||
release: ## Release new version
|
|
||||||
git tag | grep -q $(VERSION) && echo This version was released! Increase VERSION! || git tag $(VERSION) && git push origin $(VERSION) && git tag v$(VERSION) && git push origin v$(VERSION)
|
|
||||||
|
|
||||||
# Absolutely awesome: http://marmelab.com/blog/2016/02/29/auto-documented-makefile.html
|
|
||||||
help:
|
|
||||||
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
|
||||||
|
|
||||||
.DEFAULT_GOAL := build
|
|
351
vendor/github.com/avast/retry-go/README.md
generated
vendored
351
vendor/github.com/avast/retry-go/README.md
generated
vendored
@ -1,351 +0,0 @@
|
|||||||
# retry
|
|
||||||
|
|
||||||
[](https://github.com/avast/retry-go/releases/latest)
|
|
||||||
[](LICENSE.md)
|
|
||||||
[](https://travis-ci.org/avast/retry-go)
|
|
||||||
[](https://ci.appveyor.com/project/JaSei/retry-go)
|
|
||||||
[](https://goreportcard.com/report/github.com/avast/retry-go)
|
|
||||||
[](http://godoc.org/github.com/avast/retry-go)
|
|
||||||
[](https://codecov.io/github/avast/retry-go?branch=master)
|
|
||||||
[](https://sourcegraph.com/github.com/avast/retry-go?badge)
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
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`)
|
|
||||||
|
|
||||||
## 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
|
|
||||||
func BackOffDelay(n uint, config *Config) time.Duration
|
|
||||||
```
|
|
||||||
BackOffDelay is a DelayType which increases delay between consecutive retries
|
|
||||||
|
|
||||||
#### func Do
|
|
||||||
|
|
||||||
```go
|
|
||||||
func Do(retryableFunc RetryableFunc, opts ...Option) error
|
|
||||||
```
|
|
||||||
|
|
||||||
#### func FixedDelay
|
|
||||||
|
|
||||||
```go
|
|
||||||
func FixedDelay(_ uint, config *Config) time.Duration
|
|
||||||
```
|
|
||||||
FixedDelay is a DelayType which keeps delay the same through all iterations
|
|
||||||
|
|
||||||
#### func IsRecoverable
|
|
||||||
|
|
||||||
```go
|
|
||||||
func IsRecoverable(err error) bool
|
|
||||||
```
|
|
||||||
IsRecoverable checks if error is an instance of `unrecoverableError`
|
|
||||||
|
|
||||||
#### func RandomDelay
|
|
||||||
|
|
||||||
```go
|
|
||||||
func RandomDelay(_ uint, config *Config) time.Duration
|
|
||||||
```
|
|
||||||
RandomDelay is a DelayType which picks a random delay up to config.maxJitter
|
|
||||||
|
|
||||||
#### func Unrecoverable
|
|
||||||
|
|
||||||
```go
|
|
||||||
func Unrecoverable(err error) error
|
|
||||||
```
|
|
||||||
Unrecoverable wraps an error in `unrecoverableError` struct
|
|
||||||
|
|
||||||
#### type Config
|
|
||||||
|
|
||||||
```go
|
|
||||||
type Config struct {
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
#### type DelayTypeFunc
|
|
||||||
|
|
||||||
```go
|
|
||||||
type DelayTypeFunc func(n uint, config *Config) time.Duration
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
#### func CombineDelay
|
|
||||||
|
|
||||||
```go
|
|
||||||
func CombineDelay(delays ...DelayTypeFunc) DelayTypeFunc
|
|
||||||
```
|
|
||||||
CombineDelay is a DelayType the combines all of the specified delays into a new
|
|
||||||
DelayTypeFunc
|
|
||||||
|
|
||||||
#### type Error
|
|
||||||
|
|
||||||
```go
|
|
||||||
type Error []error
|
|
||||||
```
|
|
||||||
|
|
||||||
Error type represents list of errors in retry
|
|
||||||
|
|
||||||
#### func (Error) Error
|
|
||||||
|
|
||||||
```go
|
|
||||||
func (e Error) Error() string
|
|
||||||
```
|
|
||||||
Error method return string representation of Error It is an implementation of
|
|
||||||
error interface
|
|
||||||
|
|
||||||
#### func (Error) WrappedErrors
|
|
||||||
|
|
||||||
```go
|
|
||||||
func (e Error) WrappedErrors() []error
|
|
||||||
```
|
|
||||||
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.
|
|
||||||
|
|
||||||
#### type OnRetryFunc
|
|
||||||
|
|
||||||
```go
|
|
||||||
type OnRetryFunc func(n uint, err error)
|
|
||||||
```
|
|
||||||
|
|
||||||
Function signature of OnRetry function n = count of attempts
|
|
||||||
|
|
||||||
#### type Option
|
|
||||||
|
|
||||||
```go
|
|
||||||
type Option func(*Config)
|
|
||||||
```
|
|
||||||
|
|
||||||
Option represents an option for retry.
|
|
||||||
|
|
||||||
#### func Attempts
|
|
||||||
|
|
||||||
```go
|
|
||||||
func Attempts(attempts uint) Option
|
|
||||||
```
|
|
||||||
Attempts set count of retry default is 10
|
|
||||||
|
|
||||||
#### func Context
|
|
||||||
|
|
||||||
```go
|
|
||||||
func Context(ctx context.Context) Option
|
|
||||||
```
|
|
||||||
Context allow to set context of retry default are Background context
|
|
||||||
|
|
||||||
example of immediately cancellation (maybe it isn't the best example, but it describes behavior enough; I hope)
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
cancel()
|
|
||||||
|
|
||||||
retry.Do(
|
|
||||||
func() error {
|
|
||||||
...
|
|
||||||
},
|
|
||||||
retry.Context(ctx),
|
|
||||||
)
|
|
||||||
|
|
||||||
#### func Delay
|
|
||||||
|
|
||||||
```go
|
|
||||||
func Delay(delay time.Duration) Option
|
|
||||||
```
|
|
||||||
Delay set delay between retry default is 100ms
|
|
||||||
|
|
||||||
#### func DelayType
|
|
||||||
|
|
||||||
```go
|
|
||||||
func DelayType(delayType DelayTypeFunc) Option
|
|
||||||
```
|
|
||||||
DelayType set type of the delay between retries default is BackOff
|
|
||||||
|
|
||||||
#### func LastErrorOnly
|
|
||||||
|
|
||||||
```go
|
|
||||||
func LastErrorOnly(lastErrorOnly bool) Option
|
|
||||||
```
|
|
||||||
return the direct last error that came from the retried function default is
|
|
||||||
false (return wrapped errors with everything)
|
|
||||||
|
|
||||||
#### func MaxDelay
|
|
||||||
|
|
||||||
```go
|
|
||||||
func MaxDelay(maxDelay time.Duration) Option
|
|
||||||
```
|
|
||||||
MaxDelay set maximum delay between retry does not apply by default
|
|
||||||
|
|
||||||
#### func MaxJitter
|
|
||||||
|
|
||||||
```go
|
|
||||||
func MaxJitter(maxJitter time.Duration) Option
|
|
||||||
```
|
|
||||||
MaxJitter sets the maximum random Jitter between retries for RandomDelay
|
|
||||||
|
|
||||||
#### func OnRetry
|
|
||||||
|
|
||||||
```go
|
|
||||||
func OnRetry(onRetry OnRetryFunc) Option
|
|
||||||
```
|
|
||||||
OnRetry function callback are called each retry
|
|
||||||
|
|
||||||
log each retry example:
|
|
||||||
|
|
||||||
retry.Do(
|
|
||||||
func() error {
|
|
||||||
return errors.New("some error")
|
|
||||||
},
|
|
||||||
retry.OnRetry(func(n uint, err error) {
|
|
||||||
log.Printf("#%d: %s\n", n, err)
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
#### func RetryIf
|
|
||||||
|
|
||||||
```go
|
|
||||||
func RetryIf(retryIf RetryIfFunc) Option
|
|
||||||
```
|
|
||||||
RetryIf controls whether a retry should be attempted after an error (assuming
|
|
||||||
there are any retry attempts remaining)
|
|
||||||
|
|
||||||
skip retry if special error example:
|
|
||||||
|
|
||||||
retry.Do(
|
|
||||||
func() error {
|
|
||||||
return errors.New("special error")
|
|
||||||
},
|
|
||||||
retry.RetryIf(func(err error) bool {
|
|
||||||
if err.Error() == "special error" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
By default RetryIf stops execution if the error is wrapped using
|
|
||||||
`retry.Unrecoverable`, so above example may also be shortened to:
|
|
||||||
|
|
||||||
retry.Do(
|
|
||||||
func() error {
|
|
||||||
return retry.Unrecoverable(errors.New("special error"))
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
#### type RetryIfFunc
|
|
||||||
|
|
||||||
```go
|
|
||||||
type RetryIfFunc func(error) bool
|
|
||||||
```
|
|
||||||
|
|
||||||
Function signature of retry if function
|
|
||||||
|
|
||||||
#### type RetryableFunc
|
|
||||||
|
|
||||||
```go
|
|
||||||
type RetryableFunc func() error
|
|
||||||
```
|
|
||||||
|
|
||||||
Function signature of retryable function
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
Contributions are very much welcome.
|
|
||||||
|
|
||||||
### Makefile
|
|
||||||
|
|
||||||
Makefile provides several handy rules, like README.md `generator` , `setup` for prepare build/dev environment, `test`, `cover`, etc...
|
|
||||||
|
|
||||||
Try `make help` for more information.
|
|
||||||
|
|
||||||
### Before pull request
|
|
||||||
|
|
||||||
please try:
|
|
||||||
* run tests (`make test`)
|
|
||||||
* run linter (`make lint`)
|
|
||||||
* if your IDE don't automaticaly do `go fmt`, run `go fmt` (`make fmt`)
|
|
||||||
|
|
||||||
### README
|
|
||||||
|
|
||||||
README.md are generate from template [.godocdown.tmpl](.godocdown.tmpl) and code documentation via [godocdown](https://github.com/robertkrimen/godocdown).
|
|
||||||
|
|
||||||
Never edit README.md direct, because your change will be lost.
|
|
1
vendor/github.com/avast/retry-go/VERSION
generated
vendored
1
vendor/github.com/avast/retry-go/VERSION
generated
vendored
@ -1 +0,0 @@
|
|||||||
2.7.0
|
|
19
vendor/github.com/avast/retry-go/appveyor.yml
generated
vendored
19
vendor/github.com/avast/retry-go/appveyor.yml
generated
vendored
@ -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
|
|
193
vendor/github.com/avast/retry-go/options.go
generated
vendored
193
vendor/github.com/avast/retry-go/options.go
generated
vendored
@ -1,193 +0,0 @@
|
|||||||
package retry
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"math"
|
|
||||||
"math/rand"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Function signature of retry if function
|
|
||||||
type RetryIfFunc func(error) bool
|
|
||||||
|
|
||||||
// Function signature of OnRetry function
|
|
||||||
// n = count of attempts
|
|
||||||
type OnRetryFunc func(n uint, err error)
|
|
||||||
|
|
||||||
type DelayTypeFunc func(n uint, config *Config) time.Duration
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
maxBackOffN uint
|
|
||||||
}
|
|
||||||
|
|
||||||
// Option represents an option for retry.
|
|
||||||
type Option func(*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 {
|
|
||||||
return func(c *Config) {
|
|
||||||
c.lastErrorOnly = lastErrorOnly
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempts set count of retry
|
|
||||||
// default is 10
|
|
||||||
func Attempts(attempts uint) Option {
|
|
||||||
return func(c *Config) {
|
|
||||||
c.attempts = attempts
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delay set delay between retry
|
|
||||||
// default is 100ms
|
|
||||||
func Delay(delay time.Duration) Option {
|
|
||||||
return func(c *Config) {
|
|
||||||
c.delay = delay
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MaxDelay set maximum delay between retry
|
|
||||||
// does not apply by default
|
|
||||||
func MaxDelay(maxDelay time.Duration) Option {
|
|
||||||
return func(c *Config) {
|
|
||||||
c.maxDelay = maxDelay
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MaxJitter sets the maximum random Jitter between retries for RandomDelay
|
|
||||||
func MaxJitter(maxJitter time.Duration) Option {
|
|
||||||
return func(c *Config) {
|
|
||||||
c.maxJitter = maxJitter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DelayType set type of the delay between retries
|
|
||||||
// default is BackOff
|
|
||||||
func DelayType(delayType DelayTypeFunc) Option {
|
|
||||||
return func(c *Config) {
|
|
||||||
c.delayType = delayType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// BackOffDelay is a DelayType which increases delay between consecutive retries
|
|
||||||
func BackOffDelay(n uint, config *Config) time.Duration {
|
|
||||||
// 1 << 63 would overflow signed int64 (time.Duration), thus 62.
|
|
||||||
const max uint = 62
|
|
||||||
|
|
||||||
if config.maxBackOffN == 0 {
|
|
||||||
if config.delay <= 0 {
|
|
||||||
config.delay = 1
|
|
||||||
}
|
|
||||||
config.maxBackOffN = max - uint(math.Floor(math.Log2(float64(config.delay))))
|
|
||||||
}
|
|
||||||
|
|
||||||
if n > config.maxBackOffN {
|
|
||||||
n = config.maxBackOffN
|
|
||||||
}
|
|
||||||
return config.delay << n
|
|
||||||
}
|
|
||||||
|
|
||||||
// FixedDelay is a DelayType which keeps delay the same through all iterations
|
|
||||||
func FixedDelay(_ uint, config *Config) time.Duration {
|
|
||||||
return config.delay
|
|
||||||
}
|
|
||||||
|
|
||||||
// RandomDelay is a DelayType which picks a random delay up to config.maxJitter
|
|
||||||
func RandomDelay(_ uint, config *Config) time.Duration {
|
|
||||||
return time.Duration(rand.Int63n(int64(config.maxJitter)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// CombineDelay is a DelayType the combines all of the specified delays into a new DelayTypeFunc
|
|
||||||
func CombineDelay(delays ...DelayTypeFunc) DelayTypeFunc {
|
|
||||||
const maxInt64 = uint64(math.MaxInt64)
|
|
||||||
|
|
||||||
return func(n uint, config *Config) time.Duration {
|
|
||||||
var total uint64
|
|
||||||
for _, delay := range delays {
|
|
||||||
total += uint64(delay(n, config))
|
|
||||||
if total > maxInt64 {
|
|
||||||
total = maxInt64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return time.Duration(total)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnRetry function callback are called each retry
|
|
||||||
//
|
|
||||||
// log each retry example:
|
|
||||||
//
|
|
||||||
// retry.Do(
|
|
||||||
// func() error {
|
|
||||||
// return errors.New("some error")
|
|
||||||
// },
|
|
||||||
// retry.OnRetry(func(n uint, err error) {
|
|
||||||
// log.Printf("#%d: %s\n", n, err)
|
|
||||||
// }),
|
|
||||||
// )
|
|
||||||
func OnRetry(onRetry OnRetryFunc) Option {
|
|
||||||
return func(c *Config) {
|
|
||||||
c.onRetry = onRetry
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RetryIf controls whether a retry should be attempted after an error
|
|
||||||
// (assuming there are any retry attempts remaining)
|
|
||||||
//
|
|
||||||
// skip retry if special error example:
|
|
||||||
//
|
|
||||||
// retry.Do(
|
|
||||||
// func() error {
|
|
||||||
// return errors.New("special error")
|
|
||||||
// },
|
|
||||||
// retry.RetryIf(func(err error) bool {
|
|
||||||
// if err.Error() == "special error" {
|
|
||||||
// return false
|
|
||||||
// }
|
|
||||||
// return true
|
|
||||||
// })
|
|
||||||
// )
|
|
||||||
//
|
|
||||||
// By default RetryIf stops execution if the error is wrapped using `retry.Unrecoverable`,
|
|
||||||
// so above example may also be shortened to:
|
|
||||||
//
|
|
||||||
// retry.Do(
|
|
||||||
// func() error {
|
|
||||||
// return retry.Unrecoverable(errors.New("special error"))
|
|
||||||
// }
|
|
||||||
// )
|
|
||||||
func RetryIf(retryIf RetryIfFunc) Option {
|
|
||||||
return func(c *Config) {
|
|
||||||
c.retryIf = retryIf
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Context allow to set context of retry
|
|
||||||
// default are Background context
|
|
||||||
//
|
|
||||||
// example of immediately cancellation (maybe it isn't the best example, but it describes behavior enough; I hope)
|
|
||||||
// ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
// cancel()
|
|
||||||
//
|
|
||||||
// retry.Do(
|
|
||||||
// func() error {
|
|
||||||
// ...
|
|
||||||
// },
|
|
||||||
// retry.Context(ctx),
|
|
||||||
// )
|
|
||||||
func Context(ctx context.Context) Option {
|
|
||||||
return func(c *Config) {
|
|
||||||
c.context = ctx
|
|
||||||
}
|
|
||||||
}
|
|
219
vendor/github.com/avast/retry-go/retry.go
generated
vendored
219
vendor/github.com/avast/retry-go/retry.go
generated
vendored
@ -1,219 +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
|
|
||||||
|
|
||||||
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, 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
|
|
||||||
}
|
|
3
vendor/modules.txt
vendored
3
vendor/modules.txt
vendored
@ -1,6 +1,3 @@
|
|||||||
# github.com/avast/retry-go v2.7.0+incompatible
|
|
||||||
## explicit
|
|
||||||
github.com/avast/retry-go
|
|
||||||
# github.com/beorn7/perks v1.0.1
|
# github.com/beorn7/perks v1.0.1
|
||||||
## explicit; go 1.11
|
## explicit; go 1.11
|
||||||
github.com/beorn7/perks/quantile
|
github.com/beorn7/perks/quantile
|
||||||
|
Loading…
x
Reference in New Issue
Block a user