[#172] pool: Do more retries on unexpected tree service responses
1. Try its best by looking for nodes during 'GetNodeByPath' 2. Retry on 'tree not found' and other not found errors Signed-off-by: Alex Vanin <a.vanin@yadro.com>
This commit is contained in:
parent
60463871db
commit
eb5288f4a5
2 changed files with 49 additions and 4 deletions
|
@ -32,6 +32,9 @@ var (
|
||||||
|
|
||||||
// ErrNodeAccessDenied is returned from Tree service in case of access denied error.
|
// ErrNodeAccessDenied is returned from Tree service in case of access denied error.
|
||||||
ErrNodeAccessDenied = errors.New("access denied")
|
ErrNodeAccessDenied = errors.New("access denied")
|
||||||
|
|
||||||
|
// errNodeEmpty is used to trigger retry when 'GetNodeByPath' return empty result.
|
||||||
|
errNodeEmptyResult = errors.New("empty result")
|
||||||
)
|
)
|
||||||
|
|
||||||
// client represents virtual connection to the single FrostFS tree service from which Pool is formed.
|
// client represents virtual connection to the single FrostFS tree service from which Pool is formed.
|
||||||
|
@ -296,8 +299,15 @@ func (p *Pool) GetNodes(ctx context.Context, prm GetNodesParams) ([]*grpcService
|
||||||
var resp *grpcService.GetNodeByPathResponse
|
var resp *grpcService.GetNodeByPathResponse
|
||||||
if err := p.requestWithRetry(func(client grpcService.TreeServiceClient) (inErr error) {
|
if err := p.requestWithRetry(func(client grpcService.TreeServiceClient) (inErr error) {
|
||||||
resp, inErr = client.GetNodeByPath(ctx, request)
|
resp, inErr = client.GetNodeByPath(ctx, request)
|
||||||
|
// Pool wants to do retry 'GetNodeByPath' request if result is empty.
|
||||||
|
// Empty result is expected due to delayed tree service sync.
|
||||||
|
// Return an error there to trigger retry and ignore it after,
|
||||||
|
// to keep compatibility with 'GetNodeByPath' implementation.
|
||||||
|
if inErr == nil && len(resp.Body.Nodes) == 0 {
|
||||||
|
return errNodeEmptyResult
|
||||||
|
}
|
||||||
return handleError("failed to get node by path", inErr)
|
return handleError("failed to get node by path", inErr)
|
||||||
}); err != nil {
|
}); err != nil && !errors.Is(err, errNodeEmptyResult) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -749,7 +759,5 @@ func (p *Pool) requestWithRetry(fn func(client grpcService.TreeServiceClient) er
|
||||||
}
|
}
|
||||||
|
|
||||||
func shouldTryAgain(err error) bool {
|
func shouldTryAgain(err error) bool {
|
||||||
return !(err == nil ||
|
return !(err == nil || errors.Is(err, ErrNodeAccessDenied))
|
||||||
errors.Is(err, ErrNodeNotFound) ||
|
|
||||||
errors.Is(err, ErrNodeAccessDenied))
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,6 +156,43 @@ func TestRetry(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
checkIndicesAndReset(t, p, 0, 0)
|
checkIndicesAndReset(t, p, 0, 0)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("error empty result", func(t *testing.T) {
|
||||||
|
errNodes, index := 2, 0
|
||||||
|
err := p.requestWithRetry(func(client grpcService.TreeServiceClient) error {
|
||||||
|
if index < errNodes {
|
||||||
|
index++
|
||||||
|
return errNodeEmptyResult
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
checkIndicesAndReset(t, p, 0, errNodes)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("error not found", func(t *testing.T) {
|
||||||
|
errNodes, index := 2, 0
|
||||||
|
err := p.requestWithRetry(func(client grpcService.TreeServiceClient) error {
|
||||||
|
if index < errNodes {
|
||||||
|
index++
|
||||||
|
return ErrNodeNotFound
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
checkIndicesAndReset(t, p, 0, errNodes)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("error access denied", func(t *testing.T) {
|
||||||
|
var index int
|
||||||
|
err := p.requestWithRetry(func(client grpcService.TreeServiceClient) error {
|
||||||
|
index++
|
||||||
|
return ErrNodeAccessDenied
|
||||||
|
})
|
||||||
|
require.ErrorIs(t, err, ErrNodeAccessDenied)
|
||||||
|
require.Equal(t, 1, index)
|
||||||
|
checkIndicesAndReset(t, p, 0, 0)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRebalance(t *testing.T) {
|
func TestRebalance(t *testing.T) {
|
||||||
|
|
Loading…
Reference in a new issue