mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-12-01 14:47:38 +00:00
6f401daacb
### Describe Your Changes Added `--vm-backoff-retries`, `--vm-backoff-factor`, `--vm-backoff-min-duration` and `--vm-native-backoff-retries`, `--vm-native-backoff-factor`, `--vm-native-backoff-min-duration` command-line flags to the `vmctl` app. Those changes will help to configure the retry backoff policy for different situations. Related issue: https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6622 ### Checklist The following checks are **mandatory**: - [X] My change adheres [VictoriaMetrics contributing guidelines](https://docs.victoriametrics.com/contributing/). --------- Signed-off-by: hagen1778 <roman@victoriametrics.com> Co-authored-by: hagen1778 <roman@victoriametrics.com>
142 lines
3.1 KiB
Go
142 lines
3.1 KiB
Go
package backoff
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestBackoffRetry_Failure(t *testing.T) {
|
|
f := func(backoffFactor float64, backoffRetries int, cancelTimeout time.Duration, retryFunc func() error, resultExpected int) {
|
|
t.Helper()
|
|
|
|
r := &Backoff{
|
|
retries: backoffRetries,
|
|
factor: backoffFactor,
|
|
minDuration: time.Millisecond * 10,
|
|
}
|
|
ctx := context.Background()
|
|
if cancelTimeout != 0 {
|
|
newCtx, cancelFn := context.WithTimeout(context.Background(), cancelTimeout)
|
|
ctx = newCtx
|
|
defer cancelFn()
|
|
}
|
|
|
|
result, err := r.Retry(ctx, retryFunc)
|
|
if err == nil {
|
|
t.Fatalf("expecting non-nil error")
|
|
}
|
|
if result != uint64(resultExpected) {
|
|
t.Fatalf("unexpected result: got %d; want %d", result, resultExpected)
|
|
}
|
|
}
|
|
|
|
// return bad request
|
|
retryFunc := func() error {
|
|
return ErrBadRequest
|
|
}
|
|
f(0, 0, 0, retryFunc, 0)
|
|
|
|
// empty retries values
|
|
retryFunc = func() error {
|
|
time.Sleep(time.Millisecond * 100)
|
|
return nil
|
|
}
|
|
f(0, 0, 0, retryFunc, 0)
|
|
|
|
// all retries failed test
|
|
backoffFactor := 0.1
|
|
backoffRetries := 5
|
|
cancelTimeout := time.Second * 0
|
|
retryFunc = func() error {
|
|
t := time.NewTicker(time.Millisecond * 5)
|
|
defer t.Stop()
|
|
for range t.C {
|
|
return fmt.Errorf("got some error")
|
|
}
|
|
return nil
|
|
}
|
|
resultExpected := 5
|
|
f(backoffFactor, backoffRetries, cancelTimeout, retryFunc, resultExpected)
|
|
|
|
// cancel context
|
|
backoffFactor = 1.7
|
|
backoffRetries = 5
|
|
cancelTimeout = time.Millisecond * 40
|
|
retryFunc = func() error {
|
|
return fmt.Errorf("got some error")
|
|
}
|
|
resultExpected = 3
|
|
f(backoffFactor, backoffRetries, cancelTimeout, retryFunc, resultExpected)
|
|
}
|
|
|
|
func TestBackoffRetry_Success(t *testing.T) {
|
|
f := func(retryFunc func() error, resultExpected int) {
|
|
t.Helper()
|
|
|
|
r := &Backoff{
|
|
retries: 5,
|
|
factor: 1.7,
|
|
minDuration: time.Millisecond * 10,
|
|
}
|
|
ctx := context.Background()
|
|
|
|
result, err := r.Retry(ctx, retryFunc)
|
|
if err != nil {
|
|
t.Fatalf("Retry() error: %s", err)
|
|
}
|
|
if result != uint64(resultExpected) {
|
|
t.Fatalf("unexpected result: got %d; want %d", result, resultExpected)
|
|
}
|
|
}
|
|
|
|
// only one retry test
|
|
counter := 0
|
|
retryFunc := func() error {
|
|
t := time.NewTicker(time.Millisecond * 5)
|
|
defer t.Stop()
|
|
for range t.C {
|
|
counter++
|
|
if counter%2 == 0 {
|
|
return fmt.Errorf("got some error")
|
|
}
|
|
if counter%3 == 0 {
|
|
return nil
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
resultExpected := 1
|
|
f(retryFunc, resultExpected)
|
|
}
|
|
|
|
func TestBackoff_New(t *testing.T) {
|
|
f := func(retries int, factor float64, minDuration time.Duration, errExpected string) {
|
|
t.Helper()
|
|
|
|
_, err := New(retries, factor, minDuration)
|
|
if err == nil {
|
|
if errExpected != "" {
|
|
t.Fatalf("expecting non-nil error")
|
|
}
|
|
return
|
|
}
|
|
if !strings.Contains(err.Error(), errExpected) {
|
|
t.Fatalf("unexpected error: got %q; want %q", err.Error(), errExpected)
|
|
}
|
|
}
|
|
|
|
// empty retries
|
|
f(0, 1.1, time.Millisecond*10, "retries must be greater than 0")
|
|
|
|
// empty factor
|
|
f(1, 0, time.Millisecond*10, "factor must be greater than 1")
|
|
|
|
// empty minDuration
|
|
f(1, 1.1, 0, "minimum duration must be greater than 0")
|
|
|
|
// no errors
|
|
f(1, 1.1, time.Millisecond*10, "")
|
|
}
|