Merge pull request #107 from unistack-org/retries
client: determenistic retry backoff
This commit is contained in:
commit
3805d0f067
@ -2,6 +2,7 @@ package client
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"math"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/util/backoff"
|
"go.unistack.org/micro/v3/util/backoff"
|
||||||
@ -10,6 +11,20 @@ import (
|
|||||||
// BackoffFunc is the backoff call func
|
// BackoffFunc is the backoff call func
|
||||||
type BackoffFunc func(ctx context.Context, req Request, attempts int) (time.Duration, error)
|
type BackoffFunc func(ctx context.Context, req Request, attempts int) (time.Duration, error)
|
||||||
|
|
||||||
func exponentialBackoff(ctx context.Context, req Request, attempts int) (time.Duration, error) {
|
// BackoffExp using exponential backoff func
|
||||||
|
func BackoffExp(_ context.Context, _ Request, attempts int) (time.Duration, error) {
|
||||||
return backoff.Do(attempts), nil
|
return backoff.Do(attempts), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BackoffInterval specifies randomization interval for backoff func
|
||||||
|
func BackoffInterval(min time.Duration, max time.Duration) BackoffFunc {
|
||||||
|
return func(_ context.Context, _ Request, attempts int) (time.Duration, error) {
|
||||||
|
td := time.Duration(time.Duration(math.Pow(float64(attempts), math.E)) * time.Millisecond * 100)
|
||||||
|
if td < min {
|
||||||
|
return min, nil
|
||||||
|
} else if td > max {
|
||||||
|
return max, nil
|
||||||
|
}
|
||||||
|
return td, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -22,7 +22,7 @@ func TestBackoff(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < 5; i++ {
|
for i := 0; i < 5; i++ {
|
||||||
d, err := exponentialBackoff(context.TODO(), r, i)
|
d, err := BackoffExp(context.TODO(), r, i)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,8 @@ var (
|
|||||||
DefaultClient Client = NewClient()
|
DefaultClient Client = NewClient()
|
||||||
// DefaultContentType is the default content-type if not specified
|
// DefaultContentType is the default content-type if not specified
|
||||||
DefaultContentType = "application/json"
|
DefaultContentType = "application/json"
|
||||||
// DefaultBackoff is the default backoff function for retries
|
// DefaultBackoff is the default backoff function for retries (minimum 10 millisecond and maximum 5 second)
|
||||||
DefaultBackoff = exponentialBackoff
|
DefaultBackoff = BackoffInterval(10*time.Millisecond, 5*time.Second)
|
||||||
// DefaultRetry is the default check-for-retry function for retries
|
// DefaultRetry is the default check-for-retry function for retries
|
||||||
DefaultRetry = RetryNever
|
DefaultRetry = RetryNever
|
||||||
// DefaultRetries is the default number of times a request is tried
|
// DefaultRetries is the default number of times a request is tried
|
||||||
|
@ -19,18 +19,32 @@ func RetryNever(ctx context.Context, req Request, retryCount int, err error) (bo
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RetryOnError retries a request on a 500 or timeout error
|
// RetryOnError retries a request on a 500 or 408 (timeout) error
|
||||||
func RetryOnError(_ context.Context, _ Request, _ int, err error) (bool, error) {
|
func RetryOnError(_ context.Context, _ Request, _ int, err error) (bool, error) {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
me := errors.FromError(err)
|
me := errors.FromError(err)
|
||||||
switch me.Code {
|
switch me.Code {
|
||||||
// retry on timeout or internal server error
|
// retry on timeout or internal server error
|
||||||
case 408, 500:
|
case 408, 500:
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RetryOnErrors retries a request on specified error codes
|
||||||
|
func RetryOnErrors(codes ...int32) RetryFunc {
|
||||||
|
return func(_ context.Context, _ Request, _ int, err error) (bool, error) {
|
||||||
|
if err == nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
me := errors.FromError(err)
|
||||||
|
for _, code := range codes {
|
||||||
|
if me.Code == code {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user