Awesome
♻️ retry
Functional mechanism based on channels to perform actions repetitively until successful.
Usage
Quick start
var (
response *http.Response
action retry.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 {
// handle error
return
}
// work with response
Console tool for command execution with retries
This example shows how to repeat console command until successful.
$ retry --infinite -timeout 10m -backoff=lin:500ms -- /bin/sh -c 'echo "trying..."; exit $((1 + RANDOM % 10 > 5))'
See more details here.
Create HTTP client with retry
This example shows how to extend standard http.Client with retry under the hood.
type client struct {
base *http.Client
strategies []strategy.Strategy
}
func New(timeout time.Duration, strategies ...strategy.Strategy) *client {
return &client{
base: &http.Client{Timeout: timeout},
strategies: strategies,
}
}
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
}
Control database connection
This example shows how to use retry to restore database connection by database/sql/driver.Pinger
.
MustOpen := func() *sql.DB {
db, err := sql.Open("stub", "stub://test")
if err != nil {
panic(err)
}
return db
}
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))
Use context for cancellation
This example shows how to use context and retry together.
communication := make(chan error)
go service.Listen(communication)
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
}
Interrupt execution
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
Installation
$ go get github.com/kamilsk/retry
$ # or use mirror
$ egg bitbucket.org/kamilsk/retry
Update
This library is using SemVer for versioning, and it is not
BC-safe. Therefore, do not use go get -u
to update it,
use dep, glide or something similar for this purpose.
<sup id="egg">1</sup> The project is still in prototyping. ↩
made with ❤️ by OctoLab