impl: add a retry with result function (#2837)
* impl: add a retry with result function * fix ci errs
This commit is contained in:
parent
06b7c1de93
commit
5133ad83b1
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math"
|
"math"
|
||||||
|
|
@ -197,6 +198,26 @@ func Retry(operation retryFunc, retryCount int, initialDelayMilliseconds int) er
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Retry retries an operation with a return value
|
||||||
|
func RetryWithResult[T any](operation func() (T, error), retryCount int, initialDelayMilliseconds int) (result T, err error) {
|
||||||
|
result, err = operation()
|
||||||
|
if err == nil {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
for i := 0; i < retryCount; i++ {
|
||||||
|
sleepDuration := time.Millisecond * time.Duration(int(math.Pow(2, float64(i)))*initialDelayMilliseconds)
|
||||||
|
logrus.Warnf("Retrying operation after %s due to %v", sleepDuration, err)
|
||||||
|
time.Sleep(sleepDuration)
|
||||||
|
|
||||||
|
result, err = operation()
|
||||||
|
if err == nil {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, fmt.Errorf("unable to complete operation after %d attempts, last error: %w", retryCount, err)
|
||||||
|
}
|
||||||
|
|
||||||
func Lgetxattr(path string, attr string) ([]byte, error) {
|
func Lgetxattr(path string, attr string) ([]byte, error) {
|
||||||
// Start with a 128 length byte array
|
// Start with a 128 length byte array
|
||||||
dest := make([]byte, 128)
|
dest := make([]byte, 128)
|
||||||
|
|
|
||||||
|
|
@ -64,3 +64,41 @@ func TestRetry(t *testing.T) {
|
||||||
t.Fatalf("Not expecting error: %v", err)
|
t.Fatalf("Not expecting error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeRetryFuncWithResult(numFailures int) func() (int, error) {
|
||||||
|
i := -1
|
||||||
|
|
||||||
|
return func() (int, error) {
|
||||||
|
i++
|
||||||
|
if i < numFailures {
|
||||||
|
return i, fmt.Errorf("Failing with i=%v", i)
|
||||||
|
}
|
||||||
|
return i, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRetryWithResult(t *testing.T) {
|
||||||
|
// test with a function that does not return an error
|
||||||
|
result, err := RetryWithResult(makeRetryFuncWithResult(0), 0, 10)
|
||||||
|
if err != nil || result != 0 {
|
||||||
|
t.Fatalf("Got result %d and error: %v", result, err)
|
||||||
|
}
|
||||||
|
result, err = RetryWithResult(makeRetryFuncWithResult(0), 3, 10)
|
||||||
|
if err != nil || result != 0 {
|
||||||
|
t.Fatalf("Got result %d and error: %v", result, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// test with a function that returns an error twice
|
||||||
|
result, err = RetryWithResult(makeRetryFuncWithResult(2), 0, 10)
|
||||||
|
if err == nil || result != 0 {
|
||||||
|
t.Fatalf("Got result %d and error: %v", result, err)
|
||||||
|
}
|
||||||
|
result, err = RetryWithResult(makeRetryFuncWithResult(2), 1, 10)
|
||||||
|
if err == nil || result != 1 {
|
||||||
|
t.Fatalf("Got result %d and error: %v", result, err)
|
||||||
|
}
|
||||||
|
result, err = RetryWithResult(makeRetryFuncWithResult(2), 2, 10)
|
||||||
|
if err != nil || result != 2 {
|
||||||
|
t.Fatalf("Got result %d and error: %v", result, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue