2019-09-23 21:30:20 +03:00

244 lines
6.4 KiB
Markdown

> # ♻️ retry
>
> The most advanced interruptible mechanism to perform actions repetitively until successful.
[![Build][icon_build]][page_build]
[![Quality][icon_quality]][page_quality]
[![Documentation][icon_docs]][page_docs]
[![Coverage][icon_coverage]][page_coverage]
[![Awesome][icon_awesome]][page_awesome]
## 💡 Idea
The package based on [github.com/Rican7/retry](https://github.com/Rican7/retry) but fully reworked
and focused on integration with the 🚧 [breaker][] package.
Full description of the idea is available [here][design].
## 🏆 Motivation
I developed distributed systems at [Lazada](https://github.com/lazada), and later at [Avito](https://tech.avito.ru),
which communicate with each other through a network, and I need a package to make these communications more reliable.
## 🤼‍♂️ How to
### retry.Retry
```go
var response *http.Response
action := func(uint) error {
var err error
response, err = http.Get("https://github.com/kamilsk/retry")
return err
}
if err := retry.Retry(breaker.BreakByTimeout(time.Minute), action, strategy.Limit(3)); err != nil {
if err == retry.Interrupted {
// timeout exceeded
}
// handle error
}
// work with response
```
### retry.Try
```go
var response *http.Response
action := func(uint) error {
var err error
response, err = http.Get("https://github.com/kamilsk/retry")
return err
}
// you can combine multiple Breakers into one
interrupter := breaker.MultiplexTwo(
breaker.BreakByTimeout(time.Minute),
breaker.BreakBySignal(os.Interrupt),
)
defer interrupter.Close()
if err := retry.Try(interrupter, action, strategy.Limit(3)); err != nil {
if err == retry.Interrupted {
// timeout exceeded
}
// handle error
}
// work with response
```
or use Context
```go
ctx, cancel := context.WithTimeout(request.Context(), time.Minute)
defer cancel()
if err := retry.Try(ctx, action, strategy.Limit(3)); err != nil {
if err == retry.Interrupted {
// timeout exceeded
}
// handle error
}
// work with response
```
### retry.TryContext
```go
var response *http.Response
action := func(ctx context.Context, _ uint) error {
req, err := http.NewRequest(http.MethodGet, "https://github.com/kamilsk/retry", nil)
if err != nil {
return err
}
req = req.WithContext(ctx)
response, err = http.DefaultClient.Do(req)
return err
}
// you can combine Context and Breaker together
interrupter, ctx := breaker.WithContext(request.Context())
defer interrupter.Close()
if err := retry.TryContext(ctx, action, strategy.Limit(3)); err != nil {
if err == retry.Interrupted {
// timeout exceeded
}
// handle error
}
// work with response
```
### Complex example
```go
import (
"context"
"fmt"
"log"
"math/rand"
"net"
"time"
"github.com/kamilsk/retry/v4"
"github.com/kamilsk/retry/v4/backoff"
"github.com/kamilsk/retry/v4/jitter"
"github.com/kamilsk/retry/v4/strategy"
)
func main() {
what := func(uint) (err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("unexpected panic: %v", r)
}
}()
return SendRequest()
}
how := retry.How{
strategy.Limit(5),
strategy.BackoffWithJitter(
backoff.Fibonacci(10*time.Millisecond),
jitter.NormalDistribution(
rand.New(rand.NewSource(time.Now().UnixNano())),
0.25,
),
),
func(attempt uint, err error) bool {
if network, is := err.(net.Error); is {
return network.Temporary()
}
return attempt == 0 || err != nil
},
}
ctx, _ := context.WithTimeout(context.Background(), time.Second)
if err := retry.Try(ctx, what, how...); err != nil {
log.Fatal(err)
}
}
func SendRequest() error {
// communicate with some service
}
```
## 🧩 Integration
The library uses [SemVer](https://semver.org) for versioning, and it is not
[BC](https://en.wikipedia.org/wiki/Backward_compatibility)-safe through major releases.
You can use [go modules](https://github.com/golang/go/wiki/Modules) or
[dep](https://golang.github.io/dep/) to manage its version.
The **[master][legacy]** is a feature frozen branch for versions **3.3.x** and no longer maintained.
```bash
$ dep ensure -add github.com/kamilsk/retry@3.3.3
```
The **[v3][]** branch is a continuation of the **[master][legacy]** branch for versions **v3.4.x**
to better integration with [go modules](https://github.com/golang/go/wiki/Modules).
```bash
$ go get -u github.com/kamilsk/retry/v3@v3.4.4
```
The **[v4][]** branch is an actual development branch.
```bash
$ go get -u github.com/kamilsk/retry # inside GOPATH and for old Go versions
$ go get -u github.com/kamilsk/retry/v4 # inside Go module, works well since Go 1.11
$ dep ensure -add github.com/kamilsk/retry@v4.0.0
```
## 🤲 Outcomes
### Console tool for command execution with retries
This example shows how to repeat console command until successful.
```bash
$ retry -timeout 10m -backoff lin:500ms -- /bin/sh -c 'echo "trying..."; exit $((1 + RANDOM % 10 > 5))'
```
[![asciicast][cli.preview]][cli.demo]
See more details [here][cli].
---
made with ❤️ for everyone
[icon_awesome]: https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg
[icon_build]: https://travis-ci.org/kamilsk/retry.svg?branch=v4
[icon_coverage]: https://api.codeclimate.com/v1/badges/ed88afbc0754e49e9d2d/test_coverage
[icon_docs]: https://godoc.org/github.com/kamilsk/retry?status.svg
[icon_quality]: https://goreportcard.com/badge/github.com/kamilsk/retry
[page_awesome]: https://github.com/avelino/awesome-go#utilities
[page_build]: https://travis-ci.org/kamilsk/retry
[page_coverage]: https://codeclimate.com/github/kamilsk/retry/test_coverage
[page_docs]: https://godoc.org/github.com/kamilsk/retry
[page_quality]: https://goreportcard.com/report/github.com/kamilsk/retry
[breaker]: https://github.com/kamilsk/breaker
[cli]: https://github.com/kamilsk/retry.cli
[cli.demo]: https://asciinema.org/a/150367
[cli.preview]: https://asciinema.org/a/150367.png
[design]: https://www.notion.so/octolab/retry-cab5722faae445d197e44fbe0225cc98?r=0b753cbf767346f5a6fd51194829a2f3
[egg]: https://github.com/kamilsk/egg
[promo]: https://github.com/kamilsk/retry
[legacy]: https://github.com/kamilsk/retry/tree/master
[v3]: https://github.com/kamilsk/retry/tree/v3
[v4]: https://github.com/kamilsk/retry/projects/4
[tmp.docs]: https://nicedoc.io/kamilsk/retry?theme=dark
[tmp.history]: https://github.githistory.xyz/kamilsk/retry/blob/v4/README.md