-
-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
156 additions
and
129 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,13 +10,13 @@ | |
|
||
## Important news | ||
|
||
The **[master][legacy]** is a feature frozen branch for versions _3.3.x_ and no longer maintained. | ||
The **[master][legacy]** is a feature frozen branch for versions **3.3.x** and no longer maintained. | ||
|
||
```bash | ||
$ dep ensure -add github.com/kamilsk/[email protected] | ||
``` | ||
|
||
The **[v3][]** branch is a continuation of the **[master][legacy]** branch for versions _v3.4.x_ | ||
The **[v3][]** branch is a continuation of the **[master][legacy]** branch for versions **v3.4.x** | ||
to better integration with [Go Modules][gomod]. | ||
|
||
```bash | ||
|
@@ -29,136 +29,87 @@ The **[v4][]** branch is an actual development branch. | |
$ go get -u github.com/kamilsk/retry/v4 | ||
``` | ||
|
||
Version **v4.x.y** focus on integration with the 🚧 [breaker][] package. | ||
|
||
## Usage | ||
|
||
### Quick start | ||
|
||
#### retry.Retry | ||
|
||
```go | ||
var ( | ||
response *http.Response | ||
action retry.Action = func(_ uint) error { | ||
var err error | ||
response, err = http.Get("https://github.com/kamilsk/retry") | ||
return err | ||
} | ||
) | ||
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(retry.WithTimeout(time.Minute), action, strategy.Limit(10)); err != nil { | ||
if err := retry.Retry(breaker.BreakByTimeout(time.Minute), action, strategy.Limit(3)); err != nil { | ||
// handle error | ||
return | ||
} | ||
// work with response | ||
``` | ||
|
||
### Console tool for command execution with retries | ||
|
||
This example shows how to repeat console command until successful. | ||
|
||
```bash | ||
$ retry --infinite -timeout 10m -backoff=lin:500ms -- /bin/sh -c 'echo "trying..."; exit $((1 + RANDOM % 10 > 5))' | ||
``` | ||
|
||
[](https://asciinema.org/a/150367) | ||
|
||
See more details [here](cmd/retry). | ||
|
||
### Create HTTP client with retry | ||
|
||
This example shows how to extend standard http.Client with retry under the hood. | ||
#### retry.Try | ||
|
||
```go | ||
type client struct { | ||
base *http.Client | ||
strategies []strategy.Strategy | ||
} | ||
var response *http.Response | ||
|
||
func New(timeout time.Duration, strategies ...strategy.Strategy) *client { | ||
return &client{ | ||
base: &http.Client{Timeout: timeout}, | ||
strategies: strategies, | ||
} | ||
action := func(uint) error { | ||
var err error | ||
response, err = http.Get("https://github.com/kamilsk/retry") | ||
return err | ||
} | ||
interrupter := breaker.MultiplexTwo( | ||
breaker.BreakByTimeout(time.Minute), | ||
breaker.BreakBySignal(os.Interrupt), | ||
) | ||
defer interrupter.Close() | ||
|
||
func (c *client) Get(deadline <-chan struct{}, url string) (*http.Response, error) { | ||
var response *http.Response | ||
err := retry.Retry(deadline, func(uint) error { | ||
resp, err := c.base.Get(url) | ||
if err != nil { | ||
return err | ||
} | ||
response = resp | ||
return nil | ||
}, c.strategies...) | ||
return response, err | ||
if err := retry.Try(interrupter, action, strategy.Limit(3)); err != nil { | ||
// handle error | ||
} | ||
// work with response | ||
``` | ||
|
||
### Control database connection | ||
|
||
This example shows how to use retry to restore database connection by `database/sql/driver.Pinger`. | ||
#### retry.TryContext | ||
|
||
```go | ||
MustOpen := func() *sql.DB { | ||
db, err := sql.Open("stub", "stub://test") | ||
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 { | ||
panic(err) | ||
return err | ||
} | ||
return db | ||
req = req.WithContext(ctx) | ||
response, err = http.DefaultClient.Do(req) | ||
return err | ||
} | ||
ctx := breaker.WithContext( | ||
context.Background(), | ||
breaker.BreakBySignal(os.Interrupt), | ||
) | ||
|
||
go func(db *sql.DB, ctx context.Context, shutdown chan<- struct{}, frequency time.Duration, | ||
strategies ...strategy.Strategy) { | ||
|
||
defer func() { | ||
if r := recover(); r != nil { | ||
shutdown <- struct{}{} | ||
} | ||
}() | ||
|
||
ping := func(uint) error { | ||
return db.Ping() | ||
} | ||
|
||
for { | ||
if err := retry.Retry(ctx.Done(), ping, strategies...); err != nil { | ||
panic(err) | ||
} | ||
time.Sleep(frequency) | ||
} | ||
}(MustOpen(), context.Background(), shutdown, time.Millisecond, strategy.Limit(1)) | ||
if err := retry.TryContext(ctx, action, strategy.Limit(3)); err != nil { | ||
// handle error | ||
} | ||
// work with response | ||
``` | ||
|
||
### Use context for cancellation | ||
|
||
This example shows how to use context and retry together. | ||
|
||
```go | ||
communication := make(chan error) | ||
### Console tool for command execution with retries | ||
|
||
go service.Listen(communication) | ||
This example shows how to repeat console command until successful. | ||
|
||
action := func(uint) error { | ||
communication <- nil // ping | ||
return <-communication // pong | ||
} | ||
ctx := retry.WithContext(context.Background(), retry.WithTimeout(time.Second)) | ||
if err := retry.Retry(ctx.Done(), action, strategy.Delay(time.Millisecond)); err != nil { | ||
// the service does not respond within one second | ||
} | ||
```bash | ||
$ retry --infinite -timeout 10m -backoff=lin:500ms -- /bin/sh -c 'echo "trying..."; exit $((1 + RANDOM % 10 > 5))' | ||
``` | ||
|
||
### Interrupt execution | ||
[](https://asciinema.org/a/150367) | ||
|
||
```go | ||
interrupter := retry.Multiplex( | ||
retry.WithTimeout(time.Second), | ||
retry.WithSignal(os.Interrupt), | ||
) | ||
if err := retry.Retry(interrupter, func(uint) error { time.Sleep(time.Second); return nil }); err == nil { | ||
panic("press Ctrl+C") | ||
} | ||
// successful interruption | ||
``` | ||
See more details [here](cmd/retry). | ||
|
||
## Installation | ||
|
||
|
@@ -199,6 +150,7 @@ made with ❤️ by [OctoLab][octolab] | |
[v4]: https://github.com/kamilsk/retry/projects/4 | ||
|
||
[egg]: https://github.com/kamilsk/egg | ||
[breaker]: https://github.com/kamilsk/breaker | ||
[gomod]: https://github.com/golang/go/wiki/Modules | ||
|
||
[author]: https://twitter.com/ikamilsk | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package examples | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"io" | ||
"io/ioutil" | ||
"log" | ||
"net/http" | ||
"os" | ||
"time" | ||
|
||
"github.com/kamilsk/breaker" | ||
"github.com/kamilsk/retry/v4" | ||
"github.com/kamilsk/retry/v4/strategy" | ||
) | ||
|
||
func ExampleRetryQuickStart() { | ||
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 { | ||
log.Fatal(err) | ||
} | ||
|
||
_, _ = io.Copy(ioutil.Discard, response.Body) | ||
_ = response.Body.Close() | ||
|
||
fmt.Println(response.Status) | ||
// Output: 200 OK | ||
} | ||
|
||
func ExampleTryQuickStart() { | ||
var response *http.Response | ||
|
||
action := func(uint) error { | ||
var err error | ||
response, err = http.Get("https://github.com/kamilsk/retry") | ||
return err | ||
} | ||
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 { | ||
log.Fatal(err) | ||
} | ||
|
||
_, _ = io.Copy(ioutil.Discard, response.Body) | ||
_ = response.Body.Close() | ||
|
||
fmt.Println(response.Status) | ||
// Output: 200 OK | ||
} | ||
|
||
func ExampleTryContextQuickStart() { | ||
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 | ||
} | ||
ctx := breaker.WithContext( | ||
context.Background(), | ||
breaker.BreakBySignal(os.Interrupt), | ||
) | ||
|
||
if err := retry.TryContext(ctx, action, strategy.Limit(3)); err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
_, _ = io.Copy(ioutil.Discard, response.Body) | ||
_ = response.Body.Close() | ||
|
||
fmt.Println(response.Status) | ||
// Output: 200 OK | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters