lingling2012 / retry-1

♻️ The most advanced interruptible mechanism to perform actions repetitively until successful.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

♻️ retry

The most advanced interruptible mechanism to perform actions repetitively until successful.

Build Quality Documentation Coverage Awesome

💡 Idea

The package based on github.com/Rican7/retry but fully reworked and focused on integration with the 🚧 breaker package.

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

retry.Retry

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

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

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

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

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 for versioning, and it is not BC-safe through major releases. You can use go modules or dep to manage its version.

$ 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.

$ retry -timeout 10m -backoff lin:500ms -- /bin/sh -c 'echo "trying..."; exit $((1 + RANDOM % 10 > 5))'

asciicast

See more details here.


made with ❤️ for everyone

About

♻️ The most advanced interruptible mechanism to perform actions repetitively until successful.

License:MIT License


Languages

Language:Go 96.2%Language:Makefile 3.8%