mirror of
https://gitee.com/milvus-io/milvus.git
synced 2024-11-30 10:59:32 +08:00
Add unrecoverable error for retry. (#7828)
Signed-off-by: godchen <qingxiang.chen@zilliz.com>
This commit is contained in:
parent
37715a5654
commit
b3f965c7d4
@ -406,7 +406,7 @@ type loadPrefixFailKV struct {
|
||||
|
||||
// LoadWithPrefix override behavior
|
||||
func (kv *loadPrefixFailKV) LoadWithPrefix(key string) ([]string, []string, error) {
|
||||
return []string{}, []string{}, retry.NoRetryError(errors.New("mocked fail"))
|
||||
return []string{}, []string{}, retry.Unrecoverable(errors.New("mocked fail"))
|
||||
}
|
||||
|
||||
func TestRootCoordInit(t *testing.T) {
|
||||
@ -441,7 +441,7 @@ func TestRootCoordInit(t *testing.T) {
|
||||
err = core.Register()
|
||||
assert.Nil(t, err)
|
||||
core.kvBaseCreate = func(string) (kv.TxnKV, error) {
|
||||
return nil, retry.NoRetryError(errors.New("injected"))
|
||||
return nil, retry.Unrecoverable(errors.New("injected"))
|
||||
}
|
||||
err = core.Init()
|
||||
assert.NotNil(t, err)
|
||||
@ -459,7 +459,7 @@ func TestRootCoordInit(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
core.kvBaseCreate = func(root string) (kv.TxnKV, error) {
|
||||
if root == Params.MetaRootPath {
|
||||
return nil, retry.NoRetryError(errors.New("injected"))
|
||||
return nil, retry.Unrecoverable(errors.New("injected"))
|
||||
}
|
||||
return memkv.NewMemoryKV(), nil
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ var _ kv.SnapShotKV = (*suffixSnapshot)(nil)
|
||||
// newSuffixSnapshot creates a newSuffixSnapshot with provided kv
|
||||
func newSuffixSnapshot(txnKV kv.TxnKV, sep, root, snapshot string) (*suffixSnapshot, error) {
|
||||
if txnKV == nil {
|
||||
return nil, retry.NoRetryError(errors.New("txnKV is nil"))
|
||||
return nil, retry.Unrecoverable(errors.New("txnKV is nil"))
|
||||
}
|
||||
|
||||
// handles trailing / logic
|
||||
|
@ -19,7 +19,7 @@ type Config struct {
|
||||
maxSleepTime time.Duration
|
||||
}
|
||||
|
||||
func NewDefaultConfig() *Config {
|
||||
func newDefaultConfig() *Config {
|
||||
return &Config{
|
||||
attempts: uint(10),
|
||||
sleep: 200 * time.Millisecond,
|
||||
|
@ -20,20 +20,19 @@ import (
|
||||
|
||||
func Do(ctx context.Context, fn func() error, opts ...Option) error {
|
||||
|
||||
c := NewDefaultConfig()
|
||||
c := newDefaultConfig()
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(c)
|
||||
}
|
||||
el := make(ErrorList, c.attempts)
|
||||
el := make(ErrorList, 0)
|
||||
|
||||
for i := uint(0); i < c.attempts; i++ {
|
||||
if err := fn(); err != nil {
|
||||
if s, ok := err.(InterruptError); ok {
|
||||
return s.error
|
||||
if ok := IsUncoverable(err); ok {
|
||||
return err
|
||||
}
|
||||
// TODO early termination if this is unretriable error?
|
||||
el[i] = err
|
||||
el = append(el, err)
|
||||
|
||||
select {
|
||||
case <-time.After(c.sleep):
|
||||
@ -52,9 +51,11 @@ func Do(ctx context.Context, fn func() error, opts ...Option) error {
|
||||
return el
|
||||
}
|
||||
|
||||
// ErrorList for print error log
|
||||
type ErrorList []error
|
||||
|
||||
// TODO shouldn't print all retries, might be too much
|
||||
// Error method return an string representation of retry error list.
|
||||
func (el ErrorList) Error() string {
|
||||
var builder strings.Builder
|
||||
builder.WriteString("All attempts results:\n")
|
||||
@ -68,10 +69,17 @@ func (el ErrorList) Error() string {
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
type InterruptError struct {
|
||||
type unrecoverableError struct {
|
||||
error
|
||||
}
|
||||
|
||||
func NoRetryError(err error) InterruptError {
|
||||
return InterruptError{err}
|
||||
// Unrecoverable method wrap an error to unrecoverableError. This will make retry
|
||||
// quick return.
|
||||
func Unrecoverable(err error) error {
|
||||
return unrecoverableError{err}
|
||||
}
|
||||
|
||||
func IsUncoverable(err error) bool {
|
||||
_, isUnrecoverable := err.(unrecoverableError)
|
||||
return isUnrecoverable
|
||||
}
|
||||
|
@ -85,6 +85,20 @@ func TestAllError(t *testing.T) {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
func TestUnRecoveryError(t *testing.T) {
|
||||
attempts := 0
|
||||
ctx := context.Background()
|
||||
|
||||
testFn := func() error {
|
||||
attempts++
|
||||
return Unrecoverable(fmt.Errorf("some error"))
|
||||
}
|
||||
|
||||
err := Do(ctx, testFn, Attempts(3))
|
||||
assert.NotNil(t, err)
|
||||
assert.Equal(t, attempts, 1)
|
||||
}
|
||||
|
||||
func TestContextDeadline(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||
defer cancel()
|
||||
|
Loading…
Reference in New Issue
Block a user