♻️ retryThe most advanced interruptible mechanism to perform actions repetitively until successful.
💡 Idea
The package based on Rican7/retry but fully reworked and focused on integration
with the
A full description of the idea is available here.
🏆 Motivation
I developed distributed systems at Lazada, and later at Avito, which communicate with each other through a network, and I need a package to make these communications more reliable.
🤼♂️ How to
Important: retry/v5 compatible with breaker version v1.2+ and above.
retry.Do
var response *http.Response
action := func(ctx context.Context) error {
var err error
req := http.NewRequestWithContext(
ctx,
http.MethodGet, "https://github.com/kamilsk/retry",
nil,
)
response, err = http.DefaultClient.Do(req)
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.Do(interrupter, action, strategy.Limit(3)); err != nil {
if err == breaker.Interrupted {
// operation was interrupted
}
// handle error
}
// work with responseor use Context
ctx, cancel := context.WithTimeout(request.Context(), time.Minute)
defer cancel()
if err := retry.Do(ctx, action, strategy.Limit(3)); err != nil {
if err == context.Canceled || err == context.DeadlineExceeded {
// operation was interrupted
}
// handle error
}
// work with responseComplex example
import (
"context"
"database/sql"
"fmt"
"log"
"math/rand"
"net"
"time"
"github.com/kamilsk/retry/v5"
"github.com/kamilsk/retry/v5/backoff"
"github.com/kamilsk/retry/v5/jitter"
"github.com/kamilsk/retry/v5/strategy"
)
func main() {
what := 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,
),
),
strategy.CheckError(
strategy.NetworkError(strategy.Skip),
DatabaseError(),
),
}
breaker, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
if err := retry.Do(breaker, what, how...); err != nil {
log.Fatal(err)
}
}
func SendRequest(ctx context.Context) error {
// communicate with some service
}
func DatabaseError() func(error) bool {
blacklist := []error{sql.ErrNoRows, sql.ErrConnDone, sql.ErrTxDone}
return func(err error) bool {
for _, preset := range blacklist {
if err == preset {
return false
}
}
return true
}
}🧩 Integration
The library uses SemVer for versioning, and it is not BC-safe through major releases. You can use go modules to manage its version.
$ go get github.com/kamilsk/retry/v5@latest🤲 Outcomes
Console tool for command execution with retries
This example shows how to repeat console command until successful.
$ retry -timeout 10m -backoff lin:500ms -- /bin/sh -c 'echo "trying..."; exit $((1 + RANDOM % 10 > 5))'See more details here.
made with

Formed in 2009, the Archive Team (not to be confused with the archive.org Archive-It Team) is a rogue archivist collective dedicated to saving copies of rapidly dying or deleted websites for the sake of history and digital heritage. The group is 100% composed of volunteers and interested parties, and has expanded into a large amount of related projects for saving online and digital history.

